Merge branch 'v1.x' into merge

This commit is contained in:
Saúl Ibarra Corretgé 2016-08-18 09:31:26 +02:00
commit 54a501897f
21 changed files with 646 additions and 37 deletions

View File

@ -48,6 +48,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/win \
-D_WIN32_WINNT=0x0600
libuv_la_SOURCES += src/win/async.c \
src/win/core.c \
src/win/detect-wakeup.c \
src/win/dl.c \
src/win/error.c \
src/win/fs-event.c \
@ -212,6 +213,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-socket-buffer-size.c \
test/test-spawn.c \
test/test-stdio-over-pipes.c \
test/test-tcp-alloc-cb-fail.c \
test/test-tcp-bind-error.c \
test/test-tcp-bind6-error.c \
test/test-tcp-close-accept.c \
@ -243,6 +245,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-timer.c \
test/test-tmpdir.c \
test/test-tty.c \
test/test-udp-alloc-cb-fail.c \
test/test-udp-bind.c \
test/test-udp-create-socket-early.c \
test/test-udp-dgram-too-big.c \

View File

@ -224,16 +224,7 @@ Run:
## Supported Platforms
Microsoft Windows operating systems since Windows Vista. It can be built
with either Visual Studio 2015 or MinGW-w64.
Linux using the GCC toolchain.
macOS >= 10.9 using the GCC or XCode toolchain.
Solaris 121 and later using GCC toolchain.
AIX 6 and later using GCC toolchain (see notes).
Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md).
### AIX Notes
@ -252,7 +243,6 @@ See the [guidelines for contributing][].
[node.js]: http://nodejs.org/
[GYP]: http://code.google.com/p/gyp/
[Python]: https://www.python.org/downloads/
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
[x32]: https://en.wikipedia.org/wiki/X32_ABI

70
SUPPORTED_PLATFORMS.md Normal file
View File

@ -0,0 +1,70 @@
# Supported platforms
| System | Support type | Supported versions | Notes |
|---|---|---|---|
| GNU/Linux | Tier 1 | Linux >= 2.6.18 with glibc >= 2.5 | |
| macOS | Tier 1 | macOS >= 10.7 | |
| Windows | Tier 1 | Windows >= XP SP1 | MSVC 2008 and later are supported |
| FreeBSD | Tier 1 | >= 9 (see note) | |
| AIX | Tier 2 | >= 6 | Maintainers: @libuv/aix |
| z/OS | Tier 2 | >= V2R2 | Maintainers: @libuv/zos |
| Linux with musl | Tier 2 | musl >= 1.0 | |
| SunOS | Tier 2 | Solaris 121 and later | Maintainers: @libuv/sunos |
| MinGW | Tier 3 | MinGW32 and MinGW-w64 | |
| Other | Tier 3 | N/A | |
#### Note on FreeBSD 9
While FreeBSD is supported as Tier 1, FreeBSD 9 will get Tier 2 support until
it reaches end of life, in December 2016.
## Support types
* **Tier 1**: Officially supported and tested with CI. Any contributed patch
MUST NOT break such systems. These are supported by @libuv/collaborators.
* **Tier 2**: Officially supported, but not necessarily tested with CI. These
systems are maintained to the best of @libuv/collaborators ability,
without being a top priority.
* **Tier 3**: Community maintained. These systems may inadvertently break and the
community and interested parties are expected to help with the maintenance.
## Adding support for a new platform
**IMPORTANT**: Before attempting to add support for a new platform please open
an issue about it for discussion.
### Unix
I/O handling is abstracted by an internal `uv__io_t` handle. The new platform
will need to implement some of the functions, the prototypes are in
``src/unix/internal.h``.
If the new platform requires extra fields for any handle structure, create a
new include file in ``include/`` with the name ``uv-theplatform.h`` and add
the appropriate defines there.
All functionality related to the new platform must be implemented in its own
file inside ``src/unix/`` unless it's already done in a common file, in which
case adding an `ifdef` is fine.
Two build systems are supported: autotools and GYP. Ideally both need to be
supported, but if GYP does not support the new platform it can be left out.
### Windows
Windows is treated as a single platform, so adding support for a new platform
would mean adding support for a new version.
Compilation and runtime must succeed for the minimum supported version. If a
new API is to be used, it must be done optionally, only in supported versions.
### Common
Some common notes when adding support for new platforms:
* Generally libuv tries to avoid compile time checks. Do not add any to the
autotools based build system or use version checking macros.
Dynamically load functions and symbols if they are not supported by the
minimum supported version.

View File

@ -1124,8 +1124,9 @@ static void uv__read(uv_stream_t* stream) {
&& (count-- > 0)) {
assert(stream->alloc_cb != NULL);
buf = uv_buf_init(NULL, 0);
stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
if (buf.len == 0) {
if (buf.base == NULL || buf.len == 0) {
/* User indicates it can't or won't handle the read. */
stream->read_cb(stream, UV_ENOBUFS, &buf);
return;

View File

@ -165,8 +165,9 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
h.msg_name = &peer;
do {
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
if (buf.len == 0) {
if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
return;
}

View File

@ -29,6 +29,7 @@
#include "uv.h"
#include "internal.h"
#include "queue.h"
#include "handle-inl.h"
#include "req-inl.h"
@ -78,6 +79,98 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
}
#endif
static uv_loop_t** uv__loops;
static int uv__loops_size;
static int uv__loops_capacity;
#define UV__LOOPS_CHUNK_SIZE 8
static uv_mutex_t uv__loops_lock;
static void uv__loops_init() {
uv_mutex_init(&uv__loops_lock);
uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
if (!uv__loops)
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
uv__loops_size = 0;
uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
}
static int uv__loops_add(uv_loop_t* loop) {
uv_loop_t** new_loops;
int new_capacity, i;
uv_mutex_lock(&uv__loops_lock);
if (uv__loops_size == uv__loops_capacity) {
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
if (!new_loops)
goto failed_loops_realloc;
uv__loops = new_loops;
for (i = uv__loops_capacity; i < new_capacity; ++i)
uv__loops[i] = NULL;
uv__loops_capacity = new_capacity;
}
uv__loops[uv__loops_size] = loop;
++uv__loops_size;
uv_mutex_unlock(&uv__loops_lock);
return 0;
failed_loops_realloc:
uv_mutex_unlock(&uv__loops_lock);
return ERROR_OUTOFMEMORY;
}
static void uv__loops_remove(uv_loop_t* loop) {
int loop_index;
int smaller_capacity;
uv_loop_t** new_loops;
uv_mutex_lock(&uv__loops_lock);
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
if (uv__loops[loop_index] == loop)
break;
}
/* If loop was not found, ignore */
if (loop_index == uv__loops_size)
goto loop_removed;
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
uv__loops[uv__loops_size - 1] = NULL;
--uv__loops_size;
/* If we didn't grow to big skip downsizing */
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
goto loop_removed;
/* Downsize only if more than half of buffer is free */
smaller_capacity = uv__loops_capacity / 2;
if (uv__loops_size >= smaller_capacity)
goto loop_removed;
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
if (!new_loops)
goto loop_removed;
uv__loops = new_loops;
uv__loops_capacity = smaller_capacity;
loop_removed:
uv_mutex_unlock(&uv__loops_lock);
}
void uv__wake_all_loops() {
int i;
uv_loop_t* loop;
uv_mutex_lock(&uv__loops_lock);
for (i = 0; i < uv__loops_size; ++i) {
loop = uv__loops[i];
assert(loop);
if (loop->iocp != INVALID_HANDLE_VALUE)
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
}
uv_mutex_unlock(&uv__loops_lock);
}
static void uv_init(void) {
/* Tell Windows that we will handle critical errors. */
@ -99,6 +192,9 @@ static void uv_init(void) {
_CrtSetReportHook(uv__crt_dbg_report_handler);
#endif
/* Initialize tracking of all uv loops */
uv__loops_init();
/* Fetch winapi function pointers. This must be done first because other
* initialization code might need these function pointers to be loaded.
*/
@ -118,6 +214,9 @@ static void uv_init(void) {
/* Initialize utilities */
uv__util_init();
/* Initialize system wakeup detection */
uv__init_detect_system_wakeup();
}
@ -173,6 +272,10 @@ int uv_loop_init(uv_loop_t* loop) {
uv__handle_unref(&loop->wq_async);
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
err = uv__loops_add(loop);
if (err)
goto fail_async_init;
return 0;
fail_async_init:
@ -194,6 +297,8 @@ void uv__once_init(void) {
void uv__loop_close(uv_loop_t* loop) {
size_t i;
uv__loops_remove(loop);
/* close the async handle without needing an extra loop iteration */
assert(!loop->wq_async.async_sent);
loop->wq_async.close_cb = NULL;
@ -267,9 +372,13 @@ static void uv__loop_poll(uv_loop_t* loop, DWORD timeout) {
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = container_of(overlappeds[i].lpOverlapped, uv_req_t, u.io.overlapped);
uv_insert_pending_req(loop, req);
/* Package was dequeued, but see if it is not a empty package
* meant only to wake us up.
*/
if (overlappeds[i].lpOverlapped) {
req = container_of(overlappeds[i].lpOverlapped, uv_req_t, u.io.overlapped);
uv_insert_pending_req(loop, req);
}
}
/* Some time might have passed waiting for I/O,

35
src/win/detect-wakeup.c Normal file
View File

@ -0,0 +1,35 @@
#include "uv.h"
#include "internal.h"
#include "winapi.h"
static void uv__register_system_resume_callback();
void uv__init_detect_system_wakeup() {
/* Try registering system power event callback. This is the cleanest
* method, but it will only work on Win8 and above.
*/
uv__register_system_resume_callback();
}
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
ULONG Type,
PVOID Setting) {
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
uv__wake_all_loops();
return 0;
}
static void uv__register_system_resume_callback() {
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
_HPOWERNOTIFY registration_handle;
if (pPowerRegisterSuspendResumeNotification == NULL)
return;
recipient.Callback = uv__system_resume_callback;
recipient.Context = NULL;
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
&recipient,
&registration_handle);
}

View File

@ -1088,17 +1088,28 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
statbuf->st_mode = 0;
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
statbuf->st_mode |= S_IFLNK;
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
/*
* It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
* any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
* the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
* calculated below will indicate a normal directory or file, as if
* FILE_ATTRIBUTE_REPARSE_POINT was not present.
*/
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
statbuf->st_mode |= S_IFLNK;
} else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
return -1;
}
}
} else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
statbuf->st_mode |= _S_IFDIR;
statbuf->st_size = 0;
} else {
statbuf->st_mode |= _S_IFREG;
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
if (statbuf->st_mode == 0) {
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
statbuf->st_mode |= _S_IFDIR;
statbuf->st_size = 0;
} else {
statbuf->st_mode |= _S_IFREG;
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
}
}
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)

View File

@ -379,4 +379,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6;
extern struct sockaddr_in uv_addr_ip4_any_;
extern struct sockaddr_in6 uv_addr_ip6_any_;
/*
* Wake all loops with fake message
*/
void uv__wake_all_loops();
/*
* Init system wake-up detection
*/
void uv__init_detect_system_wakeup();
#endif /* UV_WIN_INTERNAL_H_ */

View File

@ -1633,8 +1633,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
}
}
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
if (buf.len == 0) {
if (buf.base == NULL || buf.len == 0) {
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
break;
}

View File

@ -476,7 +476,6 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
req = &handle->read_req;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
handle->flags |= UV_HANDLE_ZERO_READ;
buf.base = "";
buf.len = 0;
@ -974,8 +973,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
/* Do nonblocking reads until the buffer is empty */
while (handle->flags & UV_HANDLE_READING) {
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
if (buf.len == 0) {
if (buf.base == NULL || buf.len == 0) {
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
break;
}

View File

@ -502,8 +502,10 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
req = &handle->read_req;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
if (handle->tty.rd.read_line_buffer.len == 0) {
if (handle->tty.rd.read_line_buffer.base == NULL ||
handle->tty.rd.read_line_buffer.len == 0) {
handle->read_cb((uv_stream_t*) handle,
UV_ENOBUFS,
&handle->tty.rd.read_line_buffer);
@ -826,8 +828,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
/* Allocate a buffer if needed */
if (buf_used == 0) {
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
if (buf.len == 0) {
if (buf.base == NULL || buf.len == 0) {
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
goto out;
}

View File

@ -270,9 +270,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
req = &handle->recv_req;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
handle->flags |= UV_HANDLE_ZERO_READ;
buf.base = "";
buf.len = 0;
flags = MSG_PEEK;
@ -445,8 +443,9 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
/* Do a nonblocking receive */
/* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
buf = uv_buf_init(NULL, 0);
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
if (buf.len == 0) {
if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
goto done;
}

View File

@ -38,9 +38,14 @@ sNtQuerySystemInformation pNtQuerySystemInformation;
/* Kernel32 function pointers */
/* Powrprof.dll function pointer */
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
void uv_winapi_init() {
HMODULE ntdll_module;
HMODULE kernel32_module;
HMODULE powrprof_module;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
@ -99,4 +104,9 @@ void uv_winapi_init() {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
powrprof_module = LoadLibraryA("powrprof.dll");
if (powrprof_module != NULL) {
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
}
}

View File

@ -4620,6 +4620,40 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
# define ERROR_MUI_FILE_NOT_LOADED 15105
#endif
/* from powerbase.h */
#ifndef DEVICE_NOTIFY_CALLBACK
# define DEVICE_NOTIFY_CALLBACK 2
#endif
#ifndef PBT_APMRESUMEAUTOMATIC
# define PBT_APMRESUMEAUTOMATIC 18
#endif
#ifndef PBT_APMRESUMESUSPEND
# define PBT_APMRESUMESUSPEND 7
#endif
typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
PVOID Context,
ULONG Type,
PVOID Setting
);
typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
_PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
PVOID Context;
} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
typedef PVOID _HPOWERNOTIFY;
typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
(DWORD Flags,
HANDLE Recipient,
_PHPOWERNOTIFY RegistrationHandle);
/* Ntdll function pointers */
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
@ -4633,4 +4667,8 @@ extern sNtQuerySystemInformation pNtQuerySystemInformation;
/* Kernel32 function pointers */
/* Powrprof.dll function pointer */
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
#endif /* UV_WIN_WINAPI_H_ */

View File

@ -61,6 +61,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess)
TEST_DECLARE (ipc_send_recv_tcp)
TEST_DECLARE (ipc_send_recv_tcp_inprocess)
TEST_DECLARE (ipc_tcp_connection)
TEST_DECLARE (tcp_alloc_cb_fail)
TEST_DECLARE (tcp_ping_pong)
TEST_DECLARE (tcp_ping_pong_v6)
TEST_DECLARE (pipe_ping_pong)
@ -106,6 +107,7 @@ TEST_DECLARE (tcp_bind6_error_addrnotavail)
TEST_DECLARE (tcp_bind6_error_fault)
TEST_DECLARE (tcp_bind6_error_inval)
TEST_DECLARE (tcp_bind6_localhost_ok)
TEST_DECLARE (udp_alloc_cb_fail)
TEST_DECLARE (udp_bind)
TEST_DECLARE (udp_bind_reuseaddr)
TEST_DECLARE (udp_create_early)
@ -416,6 +418,8 @@ TASK_LIST_START
TEST_ENTRY (ipc_send_recv_tcp_inprocess)
TEST_ENTRY (ipc_tcp_connection)
TEST_ENTRY (tcp_alloc_cb_fail)
TEST_ENTRY (tcp_ping_pong)
TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
@ -483,6 +487,7 @@ TASK_LIST_START
TEST_ENTRY (tcp_bind6_error_inval)
TEST_ENTRY (tcp_bind6_localhost_ok)
TEST_ENTRY (udp_alloc_cb_fail)
TEST_ENTRY (udp_bind)
TEST_ENTRY (udp_bind_reuseaddr)
TEST_ENTRY (udp_create_early)

View File

@ -0,0 +1,123 @@
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uv.h"
#include "task.h"
static uv_tcp_t server;
static uv_tcp_t client;
static uv_tcp_t incoming;
static int connect_cb_called;
static int close_cb_called;
static int connection_cb_called;
static uv_write_t write_req;
static char hello[] = "HELLO!";
static void close_cb(uv_handle_t* handle) {
close_cb_called++;
}
static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
}
static void conn_alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
/* Do nothing, read_cb should be called with UV_ENOBUFS. */
}
static void conn_read_cb(uv_stream_t* stream,
ssize_t nread,
const uv_buf_t* buf) {
ASSERT(nread == UV_ENOBUFS);
ASSERT(buf->base == NULL);
ASSERT(buf->len == 0);
uv_close((uv_handle_t*) &incoming, close_cb);
uv_close((uv_handle_t*) &client, close_cb);
uv_close((uv_handle_t*) &server, close_cb);
}
static void connect_cb(uv_connect_t* req, int status) {
int r;
uv_buf_t buf;
ASSERT(status == 0);
connect_cb_called++;
buf = uv_buf_init(hello, sizeof(hello));
r = uv_write(&write_req, req->handle, &buf, 1, write_cb);
ASSERT(r == 0);
}
static void connection_cb(uv_stream_t* tcp, int status) {
ASSERT(status == 0);
ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
ASSERT(0 == uv_read_start((uv_stream_t*) &incoming,
conn_alloc_cb,
conn_read_cb));
connection_cb_called++;
}
static void start_server(void) {
struct sockaddr_in addr;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
}
TEST_IMPL(tcp_alloc_cb_fail) {
uv_connect_t connect_req;
struct sockaddr_in addr;
start_server();
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
ASSERT(0 == uv_tcp_connect(&connect_req,
&client,
(struct sockaddr*) &addr,
connect_cb));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(connect_cb_called == 1);
ASSERT(connection_cb_called == 1);
ASSERT(close_cb_called == 3);
MAKE_VALGRIND_HAPPY();
return 0;
}

View File

@ -46,13 +46,13 @@ static void close_cb(uv_handle_t* handle) {
close_cb_called++;
}
void timer_cb(uv_timer_t* handle) {
static void timer_cb(uv_timer_t* handle) {
uv_close((uv_handle_t*) &client, close_cb);
uv_close((uv_handle_t*) &server, close_cb);
uv_close((uv_handle_t*) &incoming, close_cb);
}
void write_cb(uv_write_t* req, int status) {
static void write_cb(uv_write_t* req, int status) {
if (status == 0)
write_callbacks++;
else if (status == UV_ECANCELED)

View File

@ -28,7 +28,7 @@
#else /* Unix */
# include <fcntl.h>
# include <unistd.h>
# if defined(__linux__)
# if defined(__linux__) && !defined(__ANDROID__)
# include <pty.h>
# elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
@ -260,7 +260,7 @@ TEST_IMPL(tty_file) {
}
TEST_IMPL(tty_pty) {
# if defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
# if defined(__linux__) && !defined(__ANDROID__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
int master_fd, slave_fd, r;
struct winsize w;

View File

@ -0,0 +1,197 @@
/* Copyright libuv project 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>
#include <string.h>
#define CHECK_HANDLE(handle) \
ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
static uv_udp_t server;
static uv_udp_t client;
static int cl_send_cb_called;
static int cl_recv_cb_called;
static int sv_send_cb_called;
static int sv_recv_cb_called;
static int close_cb_called;
static void sv_alloc_cb(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf) {
static char slab[65536];
CHECK_HANDLE(handle);
buf->base = slab;
buf->len = sizeof(slab);
}
static void cl_alloc_cb(uv_handle_t* handle,
size_t suggested_size,
uv_buf_t* buf) {
/* Do nothing, recv_cb should be called with UV_ENOBUFS. */
}
static void close_cb(uv_handle_t* handle) {
CHECK_HANDLE(handle);
ASSERT(1 == uv_is_closing(handle));
close_cb_called++;
}
static void cl_recv_cb(uv_udp_t* handle,
ssize_t nread,
const uv_buf_t* buf,
const struct sockaddr* addr,
unsigned flags) {
CHECK_HANDLE(handle);
ASSERT(flags == 0);
ASSERT(nread == UV_ENOBUFS);
cl_recv_cb_called++;
uv_close((uv_handle_t*) handle, close_cb);
}
static void cl_send_cb(uv_udp_send_t* req, int status) {
int r;
ASSERT(req != NULL);
ASSERT(status == 0);
CHECK_HANDLE(req->handle);
r = uv_udp_recv_start(req->handle, cl_alloc_cb, cl_recv_cb);
ASSERT(r == 0);
cl_send_cb_called++;
}
static void sv_send_cb(uv_udp_send_t* req, int status) {
ASSERT(req != NULL);
ASSERT(status == 0);
CHECK_HANDLE(req->handle);
uv_close((uv_handle_t*) req->handle, close_cb);
free(req);
sv_send_cb_called++;
}
static void sv_recv_cb(uv_udp_t* handle,
ssize_t nread,
const uv_buf_t* rcvbuf,
const struct sockaddr* addr,
unsigned flags) {
uv_udp_send_t* req;
uv_buf_t sndbuf;
int r;
if (nread < 0) {
ASSERT(0 && "unexpected error");
}
if (nread == 0) {
/* Returning unused buffer */
/* Don't count towards sv_recv_cb_called */
ASSERT(addr == NULL);
return;
}
CHECK_HANDLE(handle);
ASSERT(flags == 0);
ASSERT(addr != NULL);
ASSERT(nread == 4);
ASSERT(!memcmp("PING", rcvbuf->base, nread));
r = uv_udp_recv_stop(handle);
ASSERT(r == 0);
req = malloc(sizeof *req);
ASSERT(req != NULL);
sndbuf = uv_buf_init("PONG", 4);
r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb);
ASSERT(r == 0);
sv_recv_cb_called++;
}
TEST_IMPL(udp_alloc_cb_fail) {
struct sockaddr_in addr;
uv_udp_send_t req;
uv_buf_t buf;
int r;
ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &server);
ASSERT(r == 0);
r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
ASSERT(r == 0);
r = uv_udp_recv_start(&server, sv_alloc_cb, sv_recv_cb);
ASSERT(r == 0);
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
r = uv_udp_init(uv_default_loop(), &client);
ASSERT(r == 0);
buf = uv_buf_init("PING", 4);
r = uv_udp_send(&req,
&client,
&buf,
1,
(const struct sockaddr*) &addr,
cl_send_cb);
ASSERT(r == 0);
ASSERT(close_cb_called == 0);
ASSERT(cl_send_cb_called == 0);
ASSERT(cl_recv_cb_called == 0);
ASSERT(sv_send_cb_called == 0);
ASSERT(sv_recv_cb_called == 0);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(cl_send_cb_called == 1);
ASSERT(cl_recv_cb_called == 1);
ASSERT(sv_send_cb_called == 1);
ASSERT(sv_recv_cb_called == 1);
ASSERT(close_cb_called == 2);
MAKE_VALGRIND_HAPPY();
return 0;
}

3
uv.gyp
View File

@ -75,6 +75,7 @@
'include/uv-win.h',
'src/win/async.c',
'src/win/core.c',
'src/win/detect-wakeup.c',
'src/win/dl.c',
'src/win/error.c',
'src/win/fs.c',
@ -360,6 +361,7 @@
'test/test-spawn.c',
'test/test-fs-poll.c',
'test/test-stdio-over-pipes.c',
'test/test-tcp-alloc-cb-fail.c',
'test/test-tcp-bind-error.c',
'test/test-tcp-bind6-error.c',
'test/test-tcp-close.c',
@ -394,6 +396,7 @@
'test/test-timer-from-check.c',
'test/test-timer.c',
'test/test-tty.c',
'test/test-udp-alloc-cb-fail.c',
'test/test-udp-bind.c',
'test/test-udp-create-socket-early.c',
'test/test-udp-dgram-too-big.c',