Merge 4b50b38676 into feddddb56b
This commit is contained in:
commit
3c60eb79fa
@ -600,6 +600,7 @@ if(LIBUV_BUILD_TESTS)
|
|||||||
test/test-pipe-connect-prepare.c
|
test/test-pipe-connect-prepare.c
|
||||||
test/test-pipe-getsockname.c
|
test/test-pipe-getsockname.c
|
||||||
test/test-pipe-pending-instances.c
|
test/test-pipe-pending-instances.c
|
||||||
|
test/test-pipe-reject.c
|
||||||
test/test-pipe-sendmsg.c
|
test/test-pipe-sendmsg.c
|
||||||
test/test-pipe-server-close.c
|
test/test-pipe-server-close.c
|
||||||
test/test-pipe-set-fchmod.c
|
test/test-pipe-set-fchmod.c
|
||||||
@ -637,6 +638,8 @@ if(LIBUV_BUILD_TESTS)
|
|||||||
test/test-tcp-bind-error.c
|
test/test-tcp-bind-error.c
|
||||||
test/test-tcp-bind6-error.c
|
test/test-tcp-bind6-error.c
|
||||||
test/test-tcp-close-accept.c
|
test/test-tcp-close-accept.c
|
||||||
|
test/test-tcp-reject.c
|
||||||
|
test/test-tcp-reject-accept.c
|
||||||
test/test-tcp-close-after-read-timeout.c
|
test/test-tcp-close-after-read-timeout.c
|
||||||
test/test-tcp-close-while-connecting.c
|
test/test-tcp-close-while-connecting.c
|
||||||
test/test-tcp-close.c
|
test/test-tcp-close.c
|
||||||
|
|||||||
@ -226,6 +226,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
|||||||
test/test-pipe-connect-prepare.c \
|
test/test-pipe-connect-prepare.c \
|
||||||
test/test-pipe-getsockname.c \
|
test/test-pipe-getsockname.c \
|
||||||
test/test-pipe-pending-instances.c \
|
test/test-pipe-pending-instances.c \
|
||||||
|
test/test-pipe-reject.c \
|
||||||
test/test-pipe-sendmsg.c \
|
test/test-pipe-sendmsg.c \
|
||||||
test/test-pipe-server-close.c \
|
test/test-pipe-server-close.c \
|
||||||
test/test-pipe-close-stdout-read-stdin.c \
|
test/test-pipe-close-stdout-read-stdin.c \
|
||||||
@ -264,6 +265,8 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
|||||||
test/test-tcp-bind-error.c \
|
test/test-tcp-bind-error.c \
|
||||||
test/test-tcp-bind6-error.c \
|
test/test-tcp-bind6-error.c \
|
||||||
test/test-tcp-close-accept.c \
|
test/test-tcp-close-accept.c \
|
||||||
|
test/test-tcp-reject.c \
|
||||||
|
test/test-tcp-reject-accept.c \
|
||||||
test/test-tcp-close-while-connecting.c \
|
test/test-tcp-close-while-connecting.c \
|
||||||
test/test-tcp-close-after-read-timeout.c \
|
test/test-tcp-close-after-read-timeout.c \
|
||||||
test/test-tcp-close.c \
|
test/test-tcp-close.c \
|
||||||
|
|||||||
@ -133,6 +133,19 @@ API
|
|||||||
.. note::
|
.. note::
|
||||||
`server` and `client` must be handles running on the same loop.
|
`server` and `client` must be handles running on the same loop.
|
||||||
|
|
||||||
|
.. c:function:: int uv_reject(uv_stream_t* server)
|
||||||
|
|
||||||
|
This call is used in conjunction with :c:func:`uv_listen` to accept and
|
||||||
|
immediately discard incoming connections. Call this function after receiving
|
||||||
|
a :c:type:`uv_connection_cb`.
|
||||||
|
|
||||||
|
When the :c:type:`uv_connection_cb` callback is called it is guaranteed that
|
||||||
|
this function will complete successfully the first time. If you attempt to
|
||||||
|
use it more than once, it may fail. It is suggested to only call this
|
||||||
|
function once per :c:type:`uv_connection_cb` call. As :c:type:`uv_accept`.
|
||||||
|
|
||||||
|
.. versionadded:: REPLACEME
|
||||||
|
|
||||||
.. c:function:: int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
|
.. c:function:: int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
|
||||||
|
|
||||||
Read data from an incoming stream. The :c:type:`uv_read_cb` callback will
|
Read data from an incoming stream. The :c:type:`uv_read_cb` callback will
|
||||||
|
|||||||
@ -543,6 +543,7 @@ UV_EXTERN size_t uv_stream_get_write_queue_size(const uv_stream_t* stream);
|
|||||||
|
|
||||||
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
|
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
|
||||||
UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
|
UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
|
||||||
|
UV_EXTERN int uv_reject(uv_stream_t* server);
|
||||||
|
|
||||||
UV_EXTERN int uv_read_start(uv_stream_t*,
|
UV_EXTERN int uv_read_start(uv_stream_t*,
|
||||||
uv_alloc_cb alloc_cb,
|
uv_alloc_cb alloc_cb,
|
||||||
|
|||||||
@ -533,6 +533,54 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void uv__process_queued_fds(uv_stream_t* server) {
|
||||||
|
/* Process queued fds */
|
||||||
|
uv__stream_queued_fds_t* queued_fds;
|
||||||
|
|
||||||
|
queued_fds = server->queued_fds;
|
||||||
|
|
||||||
|
/* Read first */
|
||||||
|
server->accepted_fd = queued_fds->fds[0];
|
||||||
|
|
||||||
|
/* All read, free */
|
||||||
|
assert(queued_fds->offset > 0);
|
||||||
|
if (--queued_fds->offset == 0) {
|
||||||
|
uv__free(queued_fds);
|
||||||
|
server->queued_fds = NULL;
|
||||||
|
} else {
|
||||||
|
/* Shift rest */
|
||||||
|
memmove(queued_fds->fds,
|
||||||
|
queued_fds->fds + 1,
|
||||||
|
queued_fds->offset * sizeof(*queued_fds->fds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_reject(uv_stream_t* server) {
|
||||||
|
if (server->accepted_fd == -1)
|
||||||
|
return UV_EAGAIN;
|
||||||
|
|
||||||
|
switch (server->type) {
|
||||||
|
case UV_NAMED_PIPE:
|
||||||
|
case UV_UDP:
|
||||||
|
case UV_TCP:
|
||||||
|
uv__close(server->accepted_fd); /* Simply close the fd */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process queued fds if needed */
|
||||||
|
if (server->queued_fds != NULL) {
|
||||||
|
uv__process_queued_fds(server);
|
||||||
|
} else {
|
||||||
|
server->accepted_fd = -1;
|
||||||
|
uv__io_start(server->loop, &server->io_watcher, POLLIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -569,30 +617,12 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||||||
client->flags |= UV_HANDLE_BOUND;
|
client->flags |= UV_HANDLE_BOUND;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Process queued fds */
|
/* Process queued fds if needed */
|
||||||
if (server->queued_fds != NULL) {
|
if (server->queued_fds != NULL) {
|
||||||
uv__stream_queued_fds_t* queued_fds;
|
uv__process_queued_fds(server);
|
||||||
|
|
||||||
queued_fds = server->queued_fds;
|
|
||||||
|
|
||||||
/* Read first */
|
|
||||||
server->accepted_fd = queued_fds->fds[0];
|
|
||||||
|
|
||||||
/* All read, free */
|
|
||||||
assert(queued_fds->offset > 0);
|
|
||||||
if (--queued_fds->offset == 0) {
|
|
||||||
uv__free(queued_fds);
|
|
||||||
server->queued_fds = NULL;
|
|
||||||
} else {
|
|
||||||
/* Shift rest */
|
|
||||||
memmove(queued_fds->fds,
|
|
||||||
queued_fds->fds + 1,
|
|
||||||
queued_fds->offset * sizeof(*queued_fds->fds));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
server->accepted_fd = -1;
|
server->accepted_fd = -1;
|
||||||
if (err == 0)
|
uv__io_start(server->loop, &server->io_watcher, POLLIN);
|
||||||
uv__io_start(server->loop, &server->io_watcher, POLLIN);
|
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,46 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int uv_reject(uv_stream_t* server) {
|
||||||
|
uv_tcp_accept_t* tcp_req;
|
||||||
|
uv_pipe_accept_t* pipe_req;
|
||||||
|
|
||||||
|
if (server == NULL) {
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (server->type) {
|
||||||
|
case UV_NAMED_PIPE:
|
||||||
|
pipe_req = ((uv_pipe_t*)server)->pipe.serv.pending_accepts;
|
||||||
|
|
||||||
|
if (!pipe_req || pipe_req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
return UV_EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(pipe_req->pipeHandle);
|
||||||
|
pipe_req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||||
|
((uv_pipe_t*)server)->pipe.serv.pending_accepts = pipe_req->next_pending;
|
||||||
|
pipe_req->next_pending = NULL;
|
||||||
|
break;
|
||||||
|
case UV_TCP:
|
||||||
|
tcp_req = ((uv_tcp_t*)server)->tcp.serv.pending_accepts;
|
||||||
|
|
||||||
|
if (!tcp_req || tcp_req->accept_socket == INVALID_SOCKET) {
|
||||||
|
return UV_EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(tcp_req->accept_socket);
|
||||||
|
tcp_req->accept_socket = INVALID_SOCKET;
|
||||||
|
((uv_tcp_t*)server)->tcp.serv.pending_accepts = tcp_req->next_pending;
|
||||||
|
tcp_req->next_pending = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return UV_EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|||||||
@ -154,6 +154,8 @@ TEST_DECLARE (tcp_write_to_half_open_connection)
|
|||||||
TEST_DECLARE (tcp_unexpected_read)
|
TEST_DECLARE (tcp_unexpected_read)
|
||||||
TEST_DECLARE (tcp_read_stop)
|
TEST_DECLARE (tcp_read_stop)
|
||||||
TEST_DECLARE (tcp_read_stop_start)
|
TEST_DECLARE (tcp_read_stop_start)
|
||||||
|
TEST_DECLARE (tcp_reject)
|
||||||
|
TEST_DECLARE (tcp_reject_accept)
|
||||||
TEST_DECLARE (tcp_reuseport)
|
TEST_DECLARE (tcp_reuseport)
|
||||||
TEST_DECLARE (tcp_rst)
|
TEST_DECLARE (tcp_rst)
|
||||||
TEST_DECLARE (tcp_bind6_error_addrinuse)
|
TEST_DECLARE (tcp_bind6_error_addrinuse)
|
||||||
@ -214,6 +216,7 @@ TEST_DECLARE (pipe_getsockname_autobind)
|
|||||||
TEST_DECLARE (pipe_getsockname_blocking)
|
TEST_DECLARE (pipe_getsockname_blocking)
|
||||||
TEST_DECLARE (pipe_pending_instances)
|
TEST_DECLARE (pipe_pending_instances)
|
||||||
TEST_DECLARE (pipe_sendmsg)
|
TEST_DECLARE (pipe_sendmsg)
|
||||||
|
TEST_DECLARE (pipe_reject)
|
||||||
TEST_DECLARE (pipe_server_close)
|
TEST_DECLARE (pipe_server_close)
|
||||||
TEST_DECLARE (connection_fail)
|
TEST_DECLARE (connection_fail)
|
||||||
TEST_DECLARE (connection_fail_doesnt_auto_close)
|
TEST_DECLARE (connection_fail_doesnt_auto_close)
|
||||||
@ -771,6 +774,8 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (tcp_close_accept)
|
TEST_ENTRY (tcp_close_accept)
|
||||||
TEST_ENTRY (tcp_oob)
|
TEST_ENTRY (tcp_oob)
|
||||||
#endif
|
#endif
|
||||||
|
TEST_ENTRY (tcp_reject)
|
||||||
|
TEST_ENTRY (tcp_reject_accept)
|
||||||
TEST_ENTRY (tcp_flags)
|
TEST_ENTRY (tcp_flags)
|
||||||
TEST_ENTRY (tcp_write_to_half_open_connection)
|
TEST_ENTRY (tcp_write_to_half_open_connection)
|
||||||
TEST_ENTRY (tcp_unexpected_read)
|
TEST_ENTRY (tcp_unexpected_read)
|
||||||
@ -842,6 +847,7 @@ TASK_LIST_START
|
|||||||
TEST_ENTRY (pipe_getsockname_blocking)
|
TEST_ENTRY (pipe_getsockname_blocking)
|
||||||
TEST_ENTRY (pipe_pending_instances)
|
TEST_ENTRY (pipe_pending_instances)
|
||||||
TEST_ENTRY (pipe_sendmsg)
|
TEST_ENTRY (pipe_sendmsg)
|
||||||
|
TEST_ENTRY (pipe_reject)
|
||||||
|
|
||||||
TEST_ENTRY (connection_fail)
|
TEST_ENTRY (connection_fail)
|
||||||
TEST_ENTRY (connection_fail_doesnt_auto_close)
|
TEST_ENTRY (connection_fail_doesnt_auto_close)
|
||||||
|
|||||||
110
test/test-pipe-reject.c
Normal file
110
test/test-pipe-reject.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* Copyright libuv project and contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "task.h"
|
||||||
|
#include "uv.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uv_pipe_t pipe_handle;
|
||||||
|
uv_connect_t conn_req;
|
||||||
|
} client_t;
|
||||||
|
static uv_pipe_t server_handle;
|
||||||
|
static int connect_cb_called;
|
||||||
|
static int do_accept_called = 0;
|
||||||
|
static int connection_cb_called = 0;
|
||||||
|
static uv_pipe_t connections[2];
|
||||||
|
static client_t clients[2];
|
||||||
|
|
||||||
|
static void connect_cb(uv_connect_t* _, int status) {
|
||||||
|
ASSERT_OK(status);
|
||||||
|
connect_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connection_pipe_cb(uv_stream_t* server, int status) {
|
||||||
|
int r;
|
||||||
|
uv_pipe_t* conn;
|
||||||
|
|
||||||
|
conn = &connections[connection_cb_called];
|
||||||
|
ASSERT_OK(status);
|
||||||
|
|
||||||
|
if (connection_cb_called == 0) {
|
||||||
|
ASSERT_OK(uv_reject(server));
|
||||||
|
|
||||||
|
r = uv_pipe_init(server->loop, conn, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_accept(server, (uv_stream_t*)conn);
|
||||||
|
ASSERT(r == UV_EAGAIN);
|
||||||
|
} else {
|
||||||
|
r = uv_pipe_init(server->loop, conn, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_accept(server, (uv_stream_t*)conn);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
do_accept_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After accepting the second client, close the server handle */
|
||||||
|
if (do_accept_called == 1) {
|
||||||
|
uv_close((uv_handle_t*) &server_handle, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(pipe_reject) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
uv_loop_t* loop;
|
||||||
|
|
||||||
|
loop = uv_default_loop();
|
||||||
|
|
||||||
|
r = uv_pipe_init(loop, &server_handle, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_pipe_bind(&server_handle, TEST_PIPENAME);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_listen((uv_stream_t*)&server_handle, 128, connection_pipe_cb);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_pipe_init(loop, &clients[0].pipe_handle, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
uv_pipe_connect(&clients[0].conn_req,
|
||||||
|
&clients[0].pipe_handle,
|
||||||
|
TEST_PIPENAME,
|
||||||
|
connect_cb);
|
||||||
|
|
||||||
|
r = uv_pipe_init(loop, &clients[1].pipe_handle, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
uv_pipe_connect(&clients[1].conn_req,
|
||||||
|
&clients[1].pipe_handle,
|
||||||
|
TEST_PIPENAME,
|
||||||
|
connect_cb);
|
||||||
|
|
||||||
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
ASSERT_EQ(2, connection_cb_called);
|
||||||
|
ASSERT_EQ(2, connect_cb_called);
|
||||||
|
ASSERT_EQ(1, do_accept_called);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
137
test/test-tcp-reject-accept.c
Normal file
137
test/test-tcp-reject-accept.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uv.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static int connection_cb_called = 0;
|
||||||
|
static int do_accept_called = 0;
|
||||||
|
static int close_cb_called = 0;
|
||||||
|
static int connect_cb_called = 0;
|
||||||
|
static uv_tcp_t connections[2];
|
||||||
|
uv_tcp_t* server;
|
||||||
|
|
||||||
|
static void close_cb(uv_handle_t* handle) {
|
||||||
|
ASSERT_NOT_NULL(handle);
|
||||||
|
close_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connection_cb(uv_stream_t* tcp, int status) {
|
||||||
|
int r;
|
||||||
|
uv_tcp_t* conn;
|
||||||
|
|
||||||
|
conn = &connections[connection_cb_called];
|
||||||
|
ASSERT_OK(status);
|
||||||
|
|
||||||
|
if (connection_cb_called == 0) {
|
||||||
|
ASSERT_OK(uv_reject(tcp));
|
||||||
|
|
||||||
|
r = uv_tcp_init(tcp->loop, conn);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_accept(tcp, (uv_stream_t*)conn);
|
||||||
|
ASSERT(r == UV_EAGAIN);
|
||||||
|
} else {
|
||||||
|
r = uv_tcp_init(uv_default_loop(), conn);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_accept((uv_stream_t*)tcp, (uv_stream_t*)conn);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
do_accept_called++;
|
||||||
|
|
||||||
|
uv_close((uv_handle_t*)conn, close_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After accepting the second client, close the server handle */
|
||||||
|
if (do_accept_called == 1) {
|
||||||
|
uv_close((uv_handle_t*)tcp, close_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_server(void) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
server = malloc(sizeof *server);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||||
|
ASSERT_NOT_NULL(server);
|
||||||
|
|
||||||
|
r = uv_tcp_init(uv_default_loop(), server);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
|
||||||
|
r = uv_listen((uv_stream_t*)server, 128, connection_cb);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connect_cb(uv_connect_t* req, int status) {
|
||||||
|
ASSERT_NOT_NULL(req);
|
||||||
|
ASSERT_OK(status);
|
||||||
|
connect_cb_called++;
|
||||||
|
free(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_connect(uv_tcp_t* client) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int r;
|
||||||
|
uv_connect_t* connect_req = malloc(sizeof *connect_req);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||||
|
ASSERT_NOT_NULL(client);
|
||||||
|
ASSERT_NOT_NULL(connect_req);
|
||||||
|
|
||||||
|
ASSERT_OK(uv_tcp_init(uv_default_loop(), client));
|
||||||
|
|
||||||
|
r = uv_tcp_connect(connect_req,
|
||||||
|
client,
|
||||||
|
(const struct sockaddr*) &addr,
|
||||||
|
connect_cb);
|
||||||
|
ASSERT_OK(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(tcp_reject_accept) {
|
||||||
|
uv_tcp_t client1;
|
||||||
|
uv_tcp_t client2;
|
||||||
|
|
||||||
|
start_server();
|
||||||
|
|
||||||
|
ASSERT_OK(uv_tcp_init(uv_default_loop(), &client1));
|
||||||
|
ASSERT_OK(uv_tcp_init(uv_default_loop(), &client2));
|
||||||
|
|
||||||
|
client_connect(&client1);
|
||||||
|
client_connect(&client2);
|
||||||
|
|
||||||
|
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
ASSERT_EQ(2, connection_cb_called);
|
||||||
|
ASSERT_EQ(1, do_accept_called);
|
||||||
|
ASSERT_EQ(2, connect_cb_called);
|
||||||
|
ASSERT_EQ(2, close_cb_called);
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
83
test/test-tcp-reject.c
Normal file
83
test/test-tcp-reject.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/* Copyright libuv project and contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "task.h"
|
||||||
|
#include "uv.h"
|
||||||
|
|
||||||
|
static uv_tcp_t server;
|
||||||
|
static uv_tcp_t client;
|
||||||
|
static uv_tcp_t conn;
|
||||||
|
static int connection_cb_called;
|
||||||
|
static int connect_cb_called;
|
||||||
|
|
||||||
|
static void connect_cb(uv_connect_t* _, int status) {
|
||||||
|
ASSERT_OK(status);
|
||||||
|
connect_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connection_cb(uv_stream_t* tcp, int status) {
|
||||||
|
ASSERT_OK(status);
|
||||||
|
connection_cb_called++;
|
||||||
|
|
||||||
|
/* Reject the connection */
|
||||||
|
ASSERT_OK(uv_reject(tcp));
|
||||||
|
|
||||||
|
/* The server should not have accepted the connection */
|
||||||
|
int r = uv_tcp_init(uv_default_loop(), &conn);
|
||||||
|
r = uv_accept((uv_stream_t*)tcp, (uv_stream_t*)&conn);
|
||||||
|
ASSERT(r == UV_EAGAIN);
|
||||||
|
|
||||||
|
/* Close the server */
|
||||||
|
uv_close((uv_handle_t*) &server, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_server(void) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||||
|
|
||||||
|
ASSERT_OK(uv_tcp_init(uv_default_loop(), &server));
|
||||||
|
ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
|
||||||
|
ASSERT_OK(uv_listen((uv_stream_t*) &server, 128, connection_cb));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_IMPL(tcp_reject) {
|
||||||
|
uv_connect_t connect_req;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
start_server();
|
||||||
|
|
||||||
|
ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||||
|
|
||||||
|
ASSERT_OK(uv_tcp_init(uv_default_loop(), &client));
|
||||||
|
ASSERT_OK(uv_tcp_connect(&connect_req,
|
||||||
|
&client,
|
||||||
|
(struct sockaddr*) &addr,
|
||||||
|
connect_cb));
|
||||||
|
|
||||||
|
ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
|
||||||
|
|
||||||
|
ASSERT_EQ(1, connection_cb_called);
|
||||||
|
ASSERT_EQ(1, connect_cb_called);
|
||||||
|
|
||||||
|
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user