Browse Source

uv: upgrade to v0.11.15

v0.11.9-release
Timothy J Fontaine 11 years ago
parent
commit
1fef66ffd4
  1. 2
      deps/uv/AUTHORS
  2. 70
      deps/uv/ChangeLog
  3. 6
      deps/uv/Makefile.am
  4. 4
      deps/uv/README.md
  5. 2
      deps/uv/android-configure
  6. 3
      deps/uv/checksparse.sh
  7. 2
      deps/uv/configure.ac
  8. 0
      deps/uv/gyp_uv.py
  9. 4
      deps/uv/include/uv-darwin.h
  10. 1
      deps/uv/include/uv-unix.h
  11. 1
      deps/uv/include/uv-win.h
  12. 31
      deps/uv/include/uv.h
  13. 22
      deps/uv/samples/.gitignore
  14. 21
      deps/uv/samples/socks5-proxy/.gitignore
  15. 53
      deps/uv/samples/socks5-proxy/LICENSE
  16. 46
      deps/uv/samples/socks5-proxy/build.gyp
  17. 737
      deps/uv/samples/socks5-proxy/client.c
  18. 139
      deps/uv/samples/socks5-proxy/defs.h
  19. 131
      deps/uv/samples/socks5-proxy/getopt.c
  20. 99
      deps/uv/samples/socks5-proxy/main.c
  21. 271
      deps/uv/samples/socks5-proxy/s5.c
  22. 94
      deps/uv/samples/socks5-proxy/s5.h
  23. 241
      deps/uv/samples/socks5-proxy/server.c
  24. 72
      deps/uv/samples/socks5-proxy/util.c
  25. 12
      deps/uv/src/queue.h
  26. 2
      deps/uv/src/unix/aix.c
  27. 62
      deps/uv/src/unix/core.c
  28. 2
      deps/uv/src/unix/darwin.c
  29. 2
      deps/uv/src/unix/freebsd.c
  30. 2
      deps/uv/src/unix/fs.c
  31. 203
      deps/uv/src/unix/fsevents.c
  32. 14
      deps/uv/src/unix/internal.h
  33. 32
      deps/uv/src/unix/kqueue.c
  34. 99
      deps/uv/src/unix/linux-core.c
  35. 2
      deps/uv/src/unix/loop.c
  36. 2
      deps/uv/src/unix/netbsd.c
  37. 2
      deps/uv/src/unix/openbsd.c
  38. 6
      deps/uv/src/unix/pipe.c
  39. 21
      deps/uv/src/unix/process.c
  40. 4
      deps/uv/src/unix/stream.c
  41. 30
      deps/uv/src/unix/sunos.c
  42. 2
      deps/uv/src/unix/thread.c
  43. 34
      deps/uv/src/uv-common.c
  44. 2
      deps/uv/src/version.c
  45. 6
      deps/uv/src/win/fs.c
  46. 23
      deps/uv/src/win/process.c
  47. 23
      deps/uv/test/task.h
  48. 77
      deps/uv/test/test-close-fd.c
  49. 200
      deps/uv/test/test-fs-event.c
  50. 13
      deps/uv/test/test-list.h
  51. 50
      deps/uv/test/test-spawn.c
  52. 183
      deps/uv/test/test-tcp-close-accept.c
  53. 97
      deps/uv/test/test-util.c
  54. 101
      deps/uv/test/test-watcher-cross-stop.c
  55. 4
      deps/uv/uv.gyp
  56. 2
      deps/uv/vcbuild.bat

2
deps/uv/AUTHORS

@ -97,3 +97,5 @@ Luca Bruno <lucab@debian.org>
Reini Urban <rurban@cpanel.net> Reini Urban <rurban@cpanel.net>
Maks Naumov <maksqwe1@ukr.net> Maks Naumov <maksqwe1@ukr.net>
Sean Farrell <sean.farrell@rioki.org> Sean Farrell <sean.farrell@rioki.org>
Chris Bank <cbank@adobe.com>
Geert Jansen <geertj@gmail.com>

70
deps/uv/ChangeLog

@ -1,4 +1,72 @@
2013.10.30, Version 0.11.14 (Unstable) 2013.11.21, Version 0.11.15 (Unstable)
Changes since version 0.11.14:
* fsevents: report errors to user (Fedor Indutny)
* include: UV_FS_EVENT_RECURSIVE is a flag (Fedor Indutny)
* linux: use CLOCK_MONOTONIC_COARSE if available (Ben Noordhuis)
* build: make systemtap probes work with gyp build (Ben Noordhuis)
* unix: update events from pevents between polls (Fedor Indutny)
* fsevents: support japaneese characters in path (Chris Bank)
* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
* queue: strengthen type checks (Ben Noordhuis)
* include: remove uv_strlcat() and uv_strlcpy() (Ben Noordhuis)
* build: fix windows smp build with gyp (Geert Jansen)
* unix: return exec errors from uv_spawn, not async (Alex Crichton)
* fsevents: use native character encoding file paths (Ben Noordhuis)
* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis)
* windows: use _snwprintf(), not swprintf() (Ben Noordhuis)
* fsevents: use FlagNoDefer for FSEventStreamCreate (Fedor Indutny)
* unix: fix reopened fd bug (Fedor Indutny)
* core: fix fake watcher list and count preservation (Fedor Indutny)
* unix: set close-on-exec flag on received fds (Ben Noordhuis)
* netbsd, openbsd: enable futimes() wrapper (Ben Noordhuis)
* unix: nicer error message when kqueue() fails (Ben Noordhuis)
* samples: add socks5 proxy sample application (Ben Noordhuis)
2013.11.13, Version 0.10.19 (Stable), 33959f7524090b8d2c6c41e2400ca77e31755059
Changes since version 0.10.18:
* darwin: avoid calling GetCurrentProcess (Fedor Indutny)
* unix: update events from pevents between polls (Fedor Indutny)
* fsevents: support japaneese characters in path (Chris Bank)
* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
* build: fix windows smp build with gyp (Geert Jansen)
* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis)
* unix: fix reopened fd bug (Fedor Indutny)
* core: fix fake watcher list and count preservation (Fedor Indutny)
2013.10.30, Version 0.11.14 (Unstable), d7a6482f45c1b4eb4a853dbe1a9ce8090a35633a
Changes since version 0.11.13: Changes since version 0.11.13:

6
deps/uv/Makefile.am

@ -118,6 +118,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-barrier.c \ test/test-barrier.c \
test/test-callback-order.c \ test/test-callback-order.c \
test/test-callback-stack.c \ test/test-callback-stack.c \
test/test-close-fd.c \
test/test-close-order.c \ test/test-close-order.c \
test/test-condvar.c \ test/test-condvar.c \
test/test-connection-fail.c \ test/test-connection-fail.c \
@ -166,6 +167,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-stdio-over-pipes.c \ test/test-stdio-over-pipes.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-while-connecting.c \ test/test-tcp-close-while-connecting.c \
test/test-tcp-close.c \ test/test-tcp-close.c \
test/test-tcp-connect-error-after-write.c \ test/test-tcp-connect-error-after-write.c \
@ -193,8 +195,8 @@ test_run_tests_SOURCES = test/blackhole-server.c \
test/test-udp-open.c \ test/test-udp-open.c \
test/test-udp-options.c \ test/test-udp-options.c \
test/test-udp-send-and-recv.c \ test/test-udp-send-and-recv.c \
test/test-util.c \ test/test-walk-handles.c \
test/test-walk-handles.c test/test-watcher-cross-stop.c
test_run_tests_LDADD = libuv.la test_run_tests_LDADD = libuv.la
if WINNT if WINNT

4
deps/uv/README.md

@ -83,14 +83,14 @@ project tree manually:
Run: Run:
$ ./gyp_uv -f make $ ./gyp_uv.py -f make
$ make -C out $ make -C out
### OS X ### OS X
Run: Run:
$ ./gyp_uv -f xcode $ ./gyp_uv.py -f xcode
$ xcodebuild -project uv.xcodeproj -configuration Release -target All $ xcodebuild -project uv.xcodeproj -configuration Release -target All
### Android ### Android

2
deps/uv/android-configure

@ -16,5 +16,5 @@ export PLATFORM=android
if [ $2 -a $2 == 'gyp' ] if [ $2 -a $2 == 'gyp' ]
then then
./gyp_uv -Dtarget_arch=arm -DOS=android ./gyp_uv.py -Dtarget_arch=arm -DOS=android
fi fi

3
deps/uv/checksparse.sh

@ -132,6 +132,7 @@ test/test-stdio-over-pipes.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-while-connecting.c test/test-tcp-close-while-connecting.c
test/test-tcp-close-accept.c
test/test-tcp-close.c test/test-tcp-close.c
test/test-tcp-connect-error-after-write.c test/test-tcp-connect-error-after-write.c
test/test-tcp-connect-error.c test/test-tcp-connect-error.c
@ -158,8 +159,8 @@ test/test-udp-multicast-ttl.c
test/test-udp-open.c test/test-udp-open.c
test/test-udp-options.c test/test-udp-options.c
test/test-udp-send-and-recv.c test/test-udp-send-and-recv.c
test/test-util.c
test/test-walk-handles.c test/test-walk-handles.c
test/test-watcher-cross-stop.c
" "
case `uname -s` in case `uname -s` in

2
deps/uv/configure.ac

@ -13,7 +13,7 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT([libuv], [0.11.14], [https://github.com/joyent/libuv/issues]) AC_INIT([libuv], [0.11.15], [https://github.com/joyent/libuv/issues])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/libuv-extra-automake-flags.m4])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects] UV_EXTRA_AUTOMAKE_FLAGS)

0
deps/uv/gyp_uv → deps/uv/gyp_uv.py

4
deps/uv/include/uv-darwin.h

@ -47,10 +47,10 @@
char* realpath; \ char* realpath; \
int realpath_len; \ int realpath_len; \
int cf_flags; \ int cf_flags; \
void* cf_event; \
uv_async_t* cf_cb; \ uv_async_t* cf_cb; \
void* cf_events[2]; \
void* cf_member[2]; \ void* cf_member[2]; \
uv_sem_t _cf_reserved; \ int cf_error; \
uv_mutex_t cf_mutex; \ uv_mutex_t cf_mutex; \
#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \ #define UV_STREAM_PRIVATE_PLATFORM_FIELDS \

1
deps/uv/include/uv-unix.h

@ -287,7 +287,6 @@ typedef struct {
#define UV_PROCESS_PRIVATE_FIELDS \ #define UV_PROCESS_PRIVATE_FIELDS \
void* queue[2]; \ void* queue[2]; \
int errorno; \
int status; \ int status; \
#define UV_FS_PRIVATE_FIELDS \ #define UV_FS_PRIVATE_FIELDS \

1
deps/uv/include/uv-win.h

@ -533,7 +533,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
UV_REQ_FIELDS \ UV_REQ_FIELDS \
} exit_req; \ } exit_req; \
BYTE* child_stdio_buffer; \ BYTE* child_stdio_buffer; \
int spawn_error; \
int exit_signal; \ int exit_signal; \
HANDLE wait_handle; \ HANDLE wait_handle; \
HANDLE process_handle; \ HANDLE process_handle; \

31
deps/uv/include/uv.h

@ -567,21 +567,6 @@ UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len); UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
/*
* Utility function. Copies up to `size` characters from `src` to `dst`
* and ensures that `dst` is properly NUL terminated unless `size` is zero.
*/
UV_EXTERN size_t uv_strlcpy(char* dst, const char* src, size_t size);
/*
* Utility function. Appends `src` to `dst` and ensures that `dst` is
* properly NUL terminated unless `size` is zero or `dst` does not
* contain a NUL byte. `size` is the total length of `dst` so at most
* `size - strlen(dst) - 1` characters will be copied from `src`.
*/
UV_EXTERN size_t uv_strlcat(char* dst, const char* src, size_t size);
#define UV_STREAM_FIELDS \ #define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \ /* number of bytes queued for writing */ \
size_t write_queue_size; \ size_t write_queue_size; \
@ -1504,7 +1489,17 @@ struct uv_process_s {
UV_PROCESS_PRIVATE_FIELDS UV_PROCESS_PRIVATE_FIELDS
}; };
/* Initializes uv_process_t and starts the process. */ /*
* Initializes the uv_process_t and starts the process. If the process is
* successfully spawned, then this function will return 0. Otherwise, the
* negative error code corresponding to the reason it couldn't spawn is
* returned.
*
* Possible reasons for failing to spawn would include (but not be limited to)
* the file to execute not existing, not having permissions to use the setuid or
* setgid specified, or not having enough memory to allocate for the new
* process.
*/
UV_EXTERN int uv_spawn(uv_loop_t* loop, UV_EXTERN int uv_spawn(uv_loop_t* loop,
uv_process_t* handle, uv_process_t* handle,
const uv_process_options_t* options); const uv_process_options_t* options);
@ -1873,7 +1868,7 @@ enum uv_fs_event_flags {
* flag does not affect individual files watched. * flag does not affect individual files watched.
* This flag is currently not implemented yet on any backend. * This flag is currently not implemented yet on any backend.
*/ */
UV_FS_EVENT_WATCH_ENTRY = 1, UV_FS_EVENT_WATCH_ENTRY = 1,
/* /*
* By default uv_fs_event will try to use a kernel interface such as inotify * By default uv_fs_event will try to use a kernel interface such as inotify
@ -1889,7 +1884,7 @@ enum uv_fs_event_flags {
* (is ignoring) changes in it's subdirectories. * (is ignoring) changes in it's subdirectories.
* This flag will override this behaviour on platforms that support it. * This flag will override this behaviour on platforms that support it.
*/ */
UV_FS_EVENT_RECURSIVE = 3 UV_FS_EVENT_RECURSIVE = 4
}; };

22
deps/uv/samples/.gitignore

@ -0,0 +1,22 @@
# Copyright StrongLoop, Inc. 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.
*.mk
*.Makefile

21
deps/uv/samples/socks5-proxy/.gitignore

@ -0,0 +1,21 @@
# Copyright StrongLoop, Inc. 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.
/build/

53
deps/uv/samples/socks5-proxy/LICENSE

@ -0,0 +1,53 @@
Files: *
========
Copyright StrongLoop, Inc. 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.
Files: getopt.c
===============
Copyright (c) 1987, 1993, 1994
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

46
deps/uv/samples/socks5-proxy/build.gyp

@ -0,0 +1,46 @@
# Copyright StrongLoop, Inc. 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.
{
'targets': [
{
'dependencies': ['../../uv.gyp:libuv'],
'target_name': 's5-proxy',
'type': 'executable',
'sources': [
'client.c',
'defs.h',
'main.c',
's5.c',
's5.h',
'server.c',
'util.c',
],
'conditions': [
['OS=="win"', {
'defines': ['HAVE_UNISTD_H=0'],
'sources': ['getopt.c']
}, {
'defines': ['HAVE_UNISTD_H=1']
}]
]
}
]
}

737
deps/uv/samples/socks5-proxy/client.c

@ -0,0 +1,737 @@
/* Copyright StrongLoop, Inc. 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 "defs.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/* A connection is modeled as an abstraction on top of two simple state
* machines, one for reading and one for writing. Either state machine
* is, when active, in one of three states: busy, done or stop; the fourth
* and final state, dead, is an end state and only relevant when shutting
* down the connection. A short overview:
*
* busy done stop
* ----------|---------------------------|--------------------|------|
* readable | waiting for incoming data | have incoming data | idle |
* writable | busy writing out data | completed write | idle |
*
* We could remove the done state from the writable state machine. For our
* purposes, it's functionally equivalent to the stop state.
*
* When the connection with upstream has been established, the client_ctx
* moves into a state where incoming data from the client is sent upstream
* and vice versa, incoming data from upstream is sent to the client. In
* other words, we're just piping data back and forth. See conn_cycle()
* for details.
*
* An interesting deviation from libuv's I/O model is that reads are discrete
* rather than continuous events. In layman's terms, when a read operation
* completes, the connection stops reading until further notice.
*
* The rationale for this approach is that we have to wait until the data
* has been sent out again before we can reuse the read buffer.
*
* It also pleasingly unifies with the request model that libuv uses for
* writes and everything else; libuv may switch to a request model for
* reads in the future.
*/
enum conn_state {
c_busy, /* Busy; waiting for incoming data or for a write to complete. */
c_done, /* Done; read incoming data or write finished. */
c_stop, /* Stopped. */
c_dead
};
/* Session states. */
enum sess_state {
s_handshake, /* Wait for client handshake. */
s_handshake_auth, /* Wait for client authentication data. */
s_req_start, /* Start waiting for request data. */
s_req_parse, /* Wait for request data. */
s_req_lookup, /* Wait for upstream hostname DNS lookup to complete. */
s_req_connect, /* Wait for uv_tcp_connect() to complete. */
s_proxy_start, /* Connected. Start piping data. */
s_proxy, /* Connected. Pipe data back and forth. */
s_kill, /* Tear down session. */
s_almost_dead_0, /* Waiting for finalizers to complete. */
s_almost_dead_1, /* Waiting for finalizers to complete. */
s_almost_dead_2, /* Waiting for finalizers to complete. */
s_almost_dead_3, /* Waiting for finalizers to complete. */
s_almost_dead_4, /* Waiting for finalizers to complete. */
s_dead /* Dead. Safe to free now. */
};
static void do_next(client_ctx *cx);
static int do_handshake(client_ctx *cx);
static int do_handshake_auth(client_ctx *cx);
static int do_req_start(client_ctx *cx);
static int do_req_parse(client_ctx *cx);
static int do_req_lookup(client_ctx *cx);
static int do_req_connect_start(client_ctx *cx);
static int do_req_connect(client_ctx *cx);
static int do_proxy_start(client_ctx *cx);
static int do_proxy(client_ctx *cx);
static int do_kill(client_ctx *cx);
static int do_almost_dead(client_ctx *cx);
static int conn_cycle(const char *who, conn *a, conn *b);
static void conn_timer_reset(conn *c);
static void conn_timer_expire(uv_timer_t *handle, int status);
static void conn_getaddrinfo(conn *c, const char *hostname);
static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
int status,
struct addrinfo *ai);
static int conn_connect(conn *c);
static void conn_connect_done(uv_connect_t *req, int status);
static void conn_read(conn *c);
static void conn_read_done(uv_stream_t *handle,
ssize_t nread,
const uv_buf_t *buf);
static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf);
static void conn_write(conn *c, const void *data, unsigned int len);
static void conn_write_done(uv_write_t *req, int status);
static void conn_close(conn *c);
static void conn_close_done(uv_handle_t *handle);
/* |incoming| has been initialized by server.c when this is called. */
void client_finish_init(server_ctx *sx, client_ctx *cx) {
conn *incoming;
conn *outgoing;
cx->sx = sx;
cx->state = s_handshake;
s5_init(&cx->parser);
incoming = &cx->incoming;
incoming->client = cx;
incoming->result = 0;
incoming->rdstate = c_stop;
incoming->wrstate = c_stop;
incoming->idle_timeout = sx->idle_timeout;
CHECK(0 == uv_timer_init(sx->loop, &incoming->timer_handle));
outgoing = &cx->outgoing;
outgoing->client = cx;
outgoing->result = 0;
outgoing->rdstate = c_stop;
outgoing->wrstate = c_stop;
outgoing->idle_timeout = sx->idle_timeout;
CHECK(0 == uv_tcp_init(cx->sx->loop, &outgoing->handle.tcp));
CHECK(0 == uv_timer_init(cx->sx->loop, &outgoing->timer_handle));
/* Wait for the initial packet. */
conn_read(incoming);
}
/* This is the core state machine that drives the client <-> upstream proxy.
* We move through the initial handshake and authentication steps first and
* end up (if all goes well) in the proxy state where we're just proxying
* data between the client and upstream.
*/
static void do_next(client_ctx *cx) {
int new_state;
ASSERT(cx->state != s_dead);
switch (cx->state) {
case s_handshake:
new_state = do_handshake(cx);
break;
case s_handshake_auth:
new_state = do_handshake_auth(cx);
break;
case s_req_start:
new_state = do_req_start(cx);
break;
case s_req_parse:
new_state = do_req_parse(cx);
break;
case s_req_lookup:
new_state = do_req_lookup(cx);
break;
case s_req_connect:
new_state = do_req_connect(cx);
break;
case s_proxy_start:
new_state = do_proxy_start(cx);
break;
case s_proxy:
new_state = do_proxy(cx);
break;
case s_kill:
new_state = do_kill(cx);
break;
case s_almost_dead_0:
case s_almost_dead_1:
case s_almost_dead_2:
case s_almost_dead_3:
case s_almost_dead_4:
new_state = do_almost_dead(cx);
break;
default:
UNREACHABLE();
}
cx->state = new_state;
if (cx->state == s_dead) {
if (DEBUG_CHECKS) {
memset(cx, -1, sizeof(*cx));
}
free(cx);
}
}
static int do_handshake(client_ctx *cx) {
unsigned int methods;
conn *incoming;
s5_ctx *parser;
uint8_t *data;
size_t size;
int err;
parser = &cx->parser;
incoming = &cx->incoming;
ASSERT(incoming->rdstate == c_done);
ASSERT(incoming->wrstate == c_stop);
incoming->rdstate = c_stop;
if (incoming->result < 0) {
pr_err("read error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
data = (uint8_t *) incoming->t.buf;
size = (size_t) incoming->result;
err = s5_parse(parser, &data, &size);
if (err == s5_ok) {
conn_read(incoming);
return s_handshake; /* Need more data. */
}
if (size != 0) {
/* Could allow a round-trip saving shortcut here if the requested auth
* method is S5_AUTH_NONE (provided unauthenticated traffic is allowed.)
* Requires client support however.
*/
pr_err("junk in handshake");
return do_kill(cx);
}
if (err != s5_auth_select) {
pr_err("handshake error: %s", s5_strerror(err));
return do_kill(cx);
}
methods = s5_auth_methods(parser);
if ((methods & S5_AUTH_NONE) && can_auth_none(cx->sx, cx)) {
s5_select_auth(parser, S5_AUTH_NONE);
conn_write(incoming, "\5\0", 2); /* No auth required. */
return s_req_start;
}
if ((methods & S5_AUTH_PASSWD) && can_auth_passwd(cx->sx, cx)) {
/* TODO(bnoordhuis) Implement username/password auth. */
}
conn_write(incoming, "\5\377", 2); /* No acceptable auth. */
return s_kill;
}
/* TODO(bnoordhuis) Implement username/password auth. */
static int do_handshake_auth(client_ctx *cx) {
UNREACHABLE();
return do_kill(cx);
}
static int do_req_start(client_ctx *cx) {
conn *incoming;
incoming = &cx->incoming;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_done);
incoming->wrstate = c_stop;
if (incoming->result < 0) {
pr_err("write error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
conn_read(incoming);
return s_req_parse;
}
static int do_req_parse(client_ctx *cx) {
conn *incoming;
conn *outgoing;
s5_ctx *parser;
uint8_t *data;
size_t size;
int err;
parser = &cx->parser;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_done);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
incoming->rdstate = c_stop;
if (incoming->result < 0) {
pr_err("read error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
data = (uint8_t *) incoming->t.buf;
size = (size_t) incoming->result;
err = s5_parse(parser, &data, &size);
if (err == s5_ok) {
conn_read(incoming);
return s_req_parse; /* Need more data. */
}
if (size != 0) {
pr_err("junk in request %u", (unsigned) size);
return do_kill(cx);
}
if (err != s5_exec_cmd) {
pr_err("request error: %s", s5_strerror(err));
return do_kill(cx);
}
if (parser->cmd == s5_cmd_tcp_bind) {
/* Not supported but relatively straightforward to implement. */
pr_warn("BIND requests are not supported.");
return do_kill(cx);
}
if (parser->cmd == s5_cmd_udp_assoc) {
/* Not supported. Might be hard to implement because libuv has no
* functionality for detecting the MTU size which the RFC mandates.
*/
pr_warn("UDP ASSOC requests are not supported.");
return do_kill(cx);
}
ASSERT(parser->cmd == s5_cmd_tcp_connect);
if (parser->atyp == s5_atyp_host) {
conn_getaddrinfo(outgoing, (const char *) parser->daddr);
return s_req_lookup;
}
if (parser->atyp == s5_atyp_ipv4) {
memset(&outgoing->t.addr4, 0, sizeof(outgoing->t.addr4));
outgoing->t.addr4.sin_family = AF_INET;
outgoing->t.addr4.sin_port = htons(parser->dport);
memcpy(&outgoing->t.addr4.sin_addr,
parser->daddr,
sizeof(outgoing->t.addr4.sin_addr));
} else if (parser->atyp == s5_atyp_ipv6) {
memset(&outgoing->t.addr6, 0, sizeof(outgoing->t.addr6));
outgoing->t.addr6.sin6_family = AF_INET6;
outgoing->t.addr6.sin6_port = htons(parser->dport);
memcpy(&outgoing->t.addr6.sin6_addr,
parser->daddr,
sizeof(outgoing->t.addr6.sin6_addr));
} else {
UNREACHABLE();
}
return do_req_connect_start(cx);
}
static int do_req_lookup(client_ctx *cx) {
s5_ctx *parser;
conn *incoming;
conn *outgoing;
parser = &cx->parser;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
if (outgoing->result < 0) {
/* TODO(bnoordhuis) Escape control characters in parser->daddr. */
pr_err("lookup error for \"%s\": %s",
parser->daddr,
uv_strerror(outgoing->result));
/* Send back a 'Host unreachable' reply. */
conn_write(incoming, "\5\4\0\1\0\0\0\0\0\0", 10);
return s_kill;
}
/* Don't make assumptions about the offset of sin_port/sin6_port. */
switch (outgoing->t.addr.sa_family) {
case AF_INET:
outgoing->t.addr4.sin_port = htons(parser->dport);
break;
case AF_INET6:
outgoing->t.addr6.sin6_port = htons(parser->dport);
break;
default:
UNREACHABLE();
}
return do_req_connect_start(cx);
}
/* Assumes that cx->outgoing.t.sa contains a valid AF_INET/AF_INET6 address. */
static int do_req_connect_start(client_ctx *cx) {
conn *incoming;
conn *outgoing;
int err;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
if (!can_access(cx->sx, cx, &outgoing->t.addr)) {
pr_warn("connection not allowed by ruleset");
/* Send a 'Connection not allowed by ruleset' reply. */
conn_write(incoming, "\5\2\0\1\0\0\0\0\0\0", 10);
return s_kill;
}
err = conn_connect(outgoing);
if (err != 0) {
pr_err("connect error: %s\n", uv_strerror(err));
return do_kill(cx);
}
return s_req_connect;
}
static int do_req_connect(client_ctx *cx) {
const struct sockaddr_in6 *in6;
const struct sockaddr_in *in;
char addr_storage[sizeof(*in6)];
conn *incoming;
conn *outgoing;
uint8_t *buf;
int addrlen;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_stop);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
/* Build and send the reply. Not very pretty but gets the job done. */
buf = (uint8_t *) incoming->t.buf;
if (outgoing->result == 0) {
/* The RFC mandates that the SOCKS server must include the local port
* and address in the reply. So that's what we do.
*/
addrlen = sizeof(addr_storage);
CHECK(0 == uv_tcp_getsockname(&outgoing->handle.tcp,
(struct sockaddr *) addr_storage,
&addrlen));
buf[0] = 5; /* Version. */
buf[1] = 0; /* Success. */
buf[2] = 0; /* Reserved. */
if (addrlen == sizeof(*in)) {
buf[3] = 1; /* IPv4. */
in = (const struct sockaddr_in *) &addr_storage;
memcpy(buf + 4, &in->sin_addr, 4);
memcpy(buf + 8, &in->sin_port, 2);
conn_write(incoming, buf, 10);
} else if (addrlen == sizeof(*in6)) {
buf[3] = 4; /* IPv6. */
in6 = (const struct sockaddr_in6 *) &addr_storage;
memcpy(buf + 4, &in6->sin6_addr, 16);
memcpy(buf + 20, &in6->sin6_port, 2);
conn_write(incoming, buf, 22);
} else {
UNREACHABLE();
}
return s_proxy_start;
} else {
pr_err("upstream connection error: %s\n", uv_strerror(outgoing->result));
/* Send a 'Connection refused' reply. */
conn_write(incoming, "\5\5\0\1\0\0\0\0\0\0", 10);
return s_kill;
}
UNREACHABLE();
return s_kill;
}
static int do_proxy_start(client_ctx *cx) {
conn *incoming;
conn *outgoing;
incoming = &cx->incoming;
outgoing = &cx->outgoing;
ASSERT(incoming->rdstate == c_stop);
ASSERT(incoming->wrstate == c_done);
ASSERT(outgoing->rdstate == c_stop);
ASSERT(outgoing->wrstate == c_stop);
incoming->wrstate = c_stop;
if (incoming->result < 0) {
pr_err("write error: %s", uv_strerror(incoming->result));
return do_kill(cx);
}
conn_read(incoming);
conn_read(outgoing);
return s_proxy;
}
/* Proxy incoming data back and forth. */
static int do_proxy(client_ctx *cx) {
if (conn_cycle("client", &cx->incoming, &cx->outgoing)) {
return do_kill(cx);
}
if (conn_cycle("upstream", &cx->outgoing, &cx->incoming)) {
return do_kill(cx);
}
return s_proxy;
}
static int do_kill(client_ctx *cx) {
int new_state;
if (cx->state >= s_almost_dead_0) {
return cx->state;
}
/* Try to cancel the request. The callback still runs but if the
* cancellation succeeded, it gets called with status=UV_ECANCELED.
*/
new_state = s_almost_dead_1;
if (cx->state == s_req_lookup) {
new_state = s_almost_dead_0;
uv_cancel(&cx->outgoing.t.req);
}
conn_close(&cx->incoming);
conn_close(&cx->outgoing);
return new_state;
}
static int do_almost_dead(client_ctx *cx) {
ASSERT(cx->state >= s_almost_dead_0);
return cx->state + 1; /* Another finalizer completed. */
}
static int conn_cycle(const char *who, conn *a, conn *b) {
if (a->result < 0) {
if (a->result != UV_EOF) {
pr_err("%s error: %s", who, uv_strerror(a->result));
}
return -1;
}
if (b->result < 0) {
return -1;
}
if (a->wrstate == c_done) {
a->wrstate = c_stop;
}
/* The logic is as follows: read when we don't write and write when we don't
* read. That gives us back-pressure handling for free because if the peer
* sends data faster than we consume it, TCP congestion control kicks in.
*/
if (a->wrstate == c_stop) {
if (b->rdstate == c_stop) {
conn_read(b);
} else if (b->rdstate == c_done) {
conn_write(a, b->t.buf, b->result);
b->rdstate = c_stop; /* Triggers the call to conn_read() above. */
}
}
return 0;
}
static void conn_timer_reset(conn *c) {
CHECK(0 == uv_timer_start(&c->timer_handle,
conn_timer_expire,
c->idle_timeout,
0));
}
static void conn_timer_expire(uv_timer_t *handle, int status) {
conn *c;
CHECK(0 == status);
c = CONTAINER_OF(handle, conn, timer_handle);
c->result = UV_ETIMEDOUT;
do_next(c->client);
}
static void conn_getaddrinfo(conn *c, const char *hostname) {
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
CHECK(0 == uv_getaddrinfo(c->client->sx->loop,
&c->t.addrinfo_req,
conn_getaddrinfo_done,
hostname,
NULL,
&hints));
conn_timer_reset(c);
}
static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
int status,
struct addrinfo *ai) {
conn *c;
c = CONTAINER_OF(req, conn, t.addrinfo_req);
c->result = status;
if (status == 0) {
/* FIXME(bnoordhuis) Should try all addresses. */
if (ai->ai_family == AF_INET) {
c->t.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
} else if (ai->ai_family == AF_INET6) {
c->t.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
} else {
UNREACHABLE();
}
}
uv_freeaddrinfo(ai);
do_next(c->client);
}
/* Assumes that c->t.sa contains a valid AF_INET or AF_INET6 address. */
static int conn_connect(conn *c) {
ASSERT(c->t.addr.sa_family == AF_INET ||
c->t.addr.sa_family == AF_INET6);
conn_timer_reset(c);
return uv_tcp_connect(&c->t.connect_req,
&c->handle.tcp,
&c->t.addr,
conn_connect_done);
}
static void conn_connect_done(uv_connect_t *req, int status) {
conn *c;
if (status == UV_ECANCELED) {
return; /* Handle has been closed. */
}
c = CONTAINER_OF(req, conn, t.connect_req);
c->result = status;
do_next(c->client);
}
static void conn_read(conn *c) {
ASSERT(c->rdstate == c_stop);
CHECK(0 == uv_read_start(&c->handle.stream, conn_alloc, conn_read_done));
c->rdstate = c_busy;
conn_timer_reset(c);
}
static void conn_read_done(uv_stream_t *handle,
ssize_t nread,
const uv_buf_t *buf) {
conn *c;
c = CONTAINER_OF(handle, conn, handle);
ASSERT(c->t.buf == buf->base);
ASSERT(c->rdstate == c_busy);
c->rdstate = c_done;
c->result = nread;
uv_read_stop(&c->handle.stream);
do_next(c->client);
}
static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
conn *c;
c = CONTAINER_OF(handle, conn, handle);
ASSERT(c->rdstate == c_busy);
buf->base = c->t.buf;
buf->len = sizeof(c->t.buf);
}
static void conn_write(conn *c, const void *data, unsigned int len) {
uv_buf_t buf;
ASSERT(c->wrstate == c_stop || c->wrstate == c_done);
c->wrstate = c_busy;
/* It's okay to cast away constness here, uv_write() won't modify the
* memory.
*/
buf.base = (char *) data;
buf.len = len;
CHECK(0 == uv_write(&c->write_req,
&c->handle.stream,
&buf,
1,
conn_write_done));
conn_timer_reset(c);
}
static void conn_write_done(uv_write_t *req, int status) {
conn *c;
if (status == UV_ECANCELED) {
return; /* Handle has been closed. */
}
c = CONTAINER_OF(req, conn, write_req);
ASSERT(c->wrstate == c_busy);
c->wrstate = c_done;
c->result = status;
do_next(c->client);
}
static void conn_close(conn *c) {
ASSERT(c->rdstate != c_dead);
ASSERT(c->wrstate != c_dead);
c->rdstate = c_dead;
c->wrstate = c_dead;
c->timer_handle.data = c;
c->handle.handle.data = c;
uv_close(&c->handle.handle, conn_close_done);
uv_close((uv_handle_t *) &c->timer_handle, conn_close_done);
}
static void conn_close_done(uv_handle_t *handle) {
conn *c;
c = handle->data;
do_next(c->client);
}

139
deps/uv/samples/socks5-proxy/defs.h

@ -0,0 +1,139 @@
/* Copyright StrongLoop, Inc. 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.
*/
#ifndef DEFS_H_
#define DEFS_H_
#include "s5.h"
#include "uv.h"
#include <assert.h>
#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
#include <stddef.h> /* size_t, ssize_t */
#include <stdint.h>
#include <sys/socket.h> /* sockaddr */
struct client_ctx;
typedef struct {
const char *bind_host;
unsigned short bind_port;
unsigned int idle_timeout;
} server_config;
typedef struct {
unsigned int idle_timeout; /* Connection idle timeout in ms. */
uv_tcp_t tcp_handle;
uv_loop_t *loop;
} server_ctx;
typedef struct {
unsigned char rdstate;
unsigned char wrstate;
unsigned int idle_timeout;
struct client_ctx *client; /* Backlink to owning client context. */
ssize_t result;
union {
uv_handle_t handle;
uv_stream_t stream;
uv_tcp_t tcp;
uv_udp_t udp;
} handle;
uv_timer_t timer_handle; /* For detecting timeouts. */
uv_write_t write_req;
/* We only need one of these at a time so make them share memory. */
union {
uv_getaddrinfo_t addrinfo_req;
uv_connect_t connect_req;
uv_req_t req;
struct sockaddr_in6 addr6;
struct sockaddr_in addr4;
struct sockaddr addr;
char buf[2048]; /* Scratch space. Used to read data into. */
} t;
} conn;
typedef struct client_ctx {
unsigned int state;
server_ctx *sx; /* Backlink to owning server context. */
s5_ctx parser; /* The SOCKS protocol parser. */
conn incoming; /* Connection with the SOCKS client. */
conn outgoing; /* Connection with upstream. */
} client_ctx;
/* server.c */
int server_run(const server_config *cf, uv_loop_t *loop);
int can_auth_none(const server_ctx *sx, const client_ctx *cx);
int can_auth_passwd(const server_ctx *sx, const client_ctx *cx);
int can_access(const server_ctx *sx,
const client_ctx *cx,
const struct sockaddr *addr);
/* client.c */
void client_finish_init(server_ctx *sx, client_ctx *cx);
/* util.c */
#if defined(__GNUC__)
# define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b)))
#else
# define ATTRIBUTE_FORMAT_PRINTF(a, b)
#endif
void pr_info(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
void pr_warn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
void pr_err(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
void *xmalloc(size_t size);
/* main.c */
const char *_getprogname(void);
/* getopt.c */
#if !HAVE_UNISTD_H
extern char *optarg;
int getopt(int argc, char **argv, const char *options);
#endif
/* ASSERT() is for debug checks, CHECK() for run-time sanity checks.
* DEBUG_CHECKS is for expensive debug checks that we only want to
* enable in debug builds but still want type-checked by the compiler
* in release builds.
*/
#if defined(NDEBUG)
# define ASSERT(exp)
# define CHECK(exp) do { if (!(exp)) abort(); } while (0)
# define DEBUG_CHECKS (0)
#else
# define ASSERT(exp) assert(exp)
# define CHECK(exp) assert(exp)
# define DEBUG_CHECKS (1)
#endif
#define UNREACHABLE() CHECK(!"Unreachable code reached.")
/* This macro looks complicated but it's not: it calculates the address
* of the embedding struct through the address of the embedded struct.
* In other words, if struct A embeds struct B, then we can obtain
* the address of A by taking the address of B and subtracting the
* field offset of B in A.
*/
#define CONTAINER_OF(ptr, type, field) \
((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
#endif /* DEFS_H_ */

131
deps/uv/samples/socks5-proxy/getopt.c

@ -0,0 +1,131 @@
/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
#endif /* LIBC_SCCS and not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern const char *_getprogname(void);
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, ostr)
int nargc;
char * const nargv[];
const char *ostr;
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
place = nargv[optind];
if (optind >= nargc || *place++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
optopt = *place++;
if (optopt == '-' && *place == 0) {
/* "--" => end of options */
++optind;
place = EMSG;
return (-1);
}
if (optopt == 0) {
/* Solitary '-', treat as a '-' option
if the program (eg su) is looking for it. */
place = EMSG;
if (strchr(ostr, '-') == NULL)
return (-1);
optopt = '-';
}
} else
optopt = *place++;
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*place == 0)
++optind;
if (opterr && *ostr != ':')
(void)fprintf(stderr,
"%s: illegal option -- %c\n", _getprogname(),
optopt);
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
optarg = NULL;
if (*place == 0)
++optind;
} else {
/* Option-argument is either the rest of this argument or the
entire next argument. */
if (*place)
optarg = place;
else if (nargc > ++optind)
optarg = nargv[optind];
else {
/* option-argument absent */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
_getprogname(), optopt);
return (BADCH);
}
place = EMSG;
++optind;
}
return (optopt); /* return option letter */
}

99
deps/uv/samples/socks5-proxy/main.c

@ -0,0 +1,99 @@
/* Copyright StrongLoop, Inc. 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 "defs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h> /* getopt */
#endif
#define DEFAULT_BIND_HOST "127.0.0.1"
#define DEFAULT_BIND_PORT 1080
#define DEFAULT_IDLE_TIMEOUT (60 * 1000)
static void parse_opts(server_config *cf, int argc, char **argv);
static void usage(void);
static const char *progname = __FILE__; /* Reset in main(). */
int main(int argc, char **argv) {
server_config config;
int err;
progname = argv[0];
memset(&config, 0, sizeof(config));
config.bind_host = DEFAULT_BIND_HOST;
config.bind_port = DEFAULT_BIND_PORT;
config.idle_timeout = DEFAULT_IDLE_TIMEOUT;
parse_opts(&config, argc, argv);
err = server_run(&config, uv_default_loop());
if (err) {
exit(1);
}
return 0;
}
const char *_getprogname(void) {
return progname;
}
static void parse_opts(server_config *cf, int argc, char **argv) {
int opt;
while (-1 != (opt = getopt(argc, argv, "H:hp:"))) {
switch (opt) {
case 'H':
cf->bind_host = optarg;
break;
case 'p':
if (1 != sscanf(optarg, "%hu", &cf->bind_port)) {
pr_err("bad port number: %s", optarg);
usage();
}
break;
default:
usage();
}
}
}
static void usage(void) {
printf("Usage:\n"
"\n"
" %s [-b <address> [-h] [-p <port>]\n"
"\n"
"Options:\n"
"\n"
" -b <hostname|address> Bind to this address or hostname.\n"
" Default: \"127.0.0.1\"\n"
" -h Show this help message.\n"
" -p <port> Bind to this port number. Default: 1080\n"
"",
progname);
exit(1);
}

271
deps/uv/samples/socks5-proxy/s5.c

@ -0,0 +1,271 @@
/* Copyright StrongLoop, Inc. 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 "s5.h"
#include <errno.h>
#include <stdint.h>
#include <stdlib.h> /* abort() */
#include <string.h> /* memset() */
enum {
s5_version,
s5_nmethods,
s5_methods,
s5_auth_pw_version,
s5_auth_pw_userlen,
s5_auth_pw_username,
s5_auth_pw_passlen,
s5_auth_pw_password,
s5_req_version,
s5_req_cmd,
s5_req_reserved,
s5_req_atyp,
s5_req_atyp_host,
s5_req_daddr,
s5_req_dport0,
s5_req_dport1,
s5_dead
};
void s5_init(s5_ctx *cx) {
memset(cx, 0, sizeof(*cx));
cx->state = s5_version;
}
s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size) {
s5_err err;
uint8_t *p;
uint8_t c;
size_t i;
size_t n;
p = *data;
n = *size;
i = 0;
while (i < n) {
c = p[i];
i += 1;
switch (cx->state) {
case s5_version:
if (c != 5) {
err = s5_bad_version;
goto out;
}
cx->state = s5_nmethods;
break;
case s5_nmethods:
cx->arg0 = 0;
cx->arg1 = c; /* Number of bytes to read. */
cx->state = s5_methods;
break;
case s5_methods:
if (cx->arg0 < cx->arg1) {
switch (c) {
case 0:
cx->methods |= S5_AUTH_NONE;
break;
case 1:
cx->methods |= S5_AUTH_GSSAPI;
break;
case 2:
cx->methods |= S5_AUTH_PASSWD;
break;
/* Ignore everything we don't understand. */
}
cx->arg0 += 1;
}
if (cx->arg0 == cx->arg1) {
err = s5_auth_select;
goto out;
}
break;
case s5_auth_pw_version:
if (c != 1) {
err = s5_bad_version;
goto out;
}
cx->state = s5_auth_pw_userlen;
break;
case s5_auth_pw_userlen:
cx->arg0 = 0;
cx->userlen = c;
cx->state = s5_auth_pw_username;
break;
case s5_auth_pw_username:
if (cx->arg0 < cx->userlen) {
cx->username[cx->arg0] = c;
cx->arg0 += 1;
}
if (cx->arg0 == cx->userlen) {
cx->username[cx->userlen] = '\0';
cx->state = s5_auth_pw_passlen;
}
break;
case s5_auth_pw_passlen:
cx->arg0 = 0;
cx->passlen = c;
cx->state = s5_auth_pw_password;
break;
case s5_auth_pw_password:
if (cx->arg0 < cx->passlen) {
cx->password[cx->arg0] = c;
cx->arg0 += 1;
}
if (cx->arg0 == cx->passlen) {
cx->password[cx->passlen] = '\0';
cx->state = s5_req_version;
err = s5_auth_verify;
goto out;
}
break;
case s5_req_version:
if (c != 5) {
err = s5_bad_version;
goto out;
}
cx->state = s5_req_cmd;
break;
case s5_req_cmd:
switch (c) {
case 1: /* TCP connect */
cx->cmd = s5_cmd_tcp_connect;
break;
case 3: /* UDP associate */
cx->cmd = s5_cmd_udp_assoc;
break;
default:
err = s5_bad_cmd;
goto out;
}
cx->state = s5_req_reserved;
break;
case s5_req_reserved:
cx->state = s5_req_atyp;
break;
case s5_req_atyp:
cx->arg0 = 0;
switch (c) {
case 1: /* IPv4, four octets. */
cx->state = s5_req_daddr;
cx->atyp = s5_atyp_ipv4;
cx->arg1 = 4;
break;
case 3: /* Hostname. First byte is length. */
cx->state = s5_req_atyp_host;
cx->atyp = s5_atyp_host;
cx->arg1 = 0;
break;
case 4: /* IPv6, sixteen octets. */
cx->state = s5_req_daddr;
cx->atyp = s5_atyp_ipv6;
cx->arg1 = 16;
break;
default:
err = s5_bad_atyp;
goto out;
}
break;
case s5_req_atyp_host:
cx->arg1 = c;
cx->state = s5_req_daddr;
break;
case s5_req_daddr:
if (cx->arg0 < cx->arg1) {
cx->daddr[cx->arg0] = c;
cx->arg0 += 1;
}
if (cx->arg0 == cx->arg1) {
cx->daddr[cx->arg1] = '\0';
cx->state = s5_req_dport0;
}
break;
case s5_req_dport0:
cx->dport = c << 8;
cx->state = s5_req_dport1;
break;
case s5_req_dport1:
cx->dport |= c;
cx->state = s5_dead;
err = s5_exec_cmd;
goto out;
case s5_dead:
break;
default:
abort();
}
}
err = s5_ok;
out:
*data = p + i;
*size = n - i;
return err;
}
unsigned int s5_auth_methods(const s5_ctx *cx) {
return cx->methods;
}
int s5_select_auth(s5_ctx *cx, s5_auth_method method) {
int err;
err = 0;
switch (method) {
case S5_AUTH_NONE:
cx->state = s5_req_version;
break;
case S5_AUTH_PASSWD:
cx->state = s5_auth_pw_version;
break;
default:
err = -EINVAL;
}
return err;
}
const char *s5_strerror(s5_err err) {
#define S5_ERR_GEN(_, name, errmsg) case s5_ ## name: return errmsg;
switch (err) {
S5_ERR_MAP(S5_ERR_GEN)
default: ; /* Silence s5_max_errors -Wswitch warning. */
}
#undef S5_ERR_GEN
return "Unknown error.";
}

94
deps/uv/samples/socks5-proxy/s5.h

@ -0,0 +1,94 @@
/* Copyright StrongLoop, Inc. 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.
*/
#ifndef S5_H_
#define S5_H_
#include <stddef.h>
#include <stdint.h>
#define S5_ERR_MAP(V) \
V(-1, bad_version, "Bad protocol version.") \
V(-2, bad_cmd, "Bad protocol command.") \
V(-3, bad_atyp, "Bad address type.") \
V(0, ok, "No error.") \
V(1, auth_select, "Select authentication method.") \
V(2, auth_verify, "Verify authentication.") \
V(3, exec_cmd, "Execute command.") \
typedef enum {
#define S5_ERR_GEN(code, name, _) s5_ ## name = code,
S5_ERR_MAP(S5_ERR_GEN)
#undef S5_ERR_GEN
s5_max_errors
} s5_err;
typedef enum {
S5_AUTH_NONE = 1 << 0,
S5_AUTH_GSSAPI = 1 << 1,
S5_AUTH_PASSWD = 1 << 2
} s5_auth_method;
typedef enum {
s5_auth_allow,
s5_auth_deny
} s5_auth_result;
typedef enum {
s5_atyp_ipv4,
s5_atyp_ipv6,
s5_atyp_host
} s5_atyp;
typedef enum {
s5_cmd_tcp_connect,
s5_cmd_tcp_bind,
s5_cmd_udp_assoc
} s5_cmd;
typedef struct {
uint32_t arg0; /* Scratch space for the state machine. */
uint32_t arg1; /* Scratch space for the state machine. */
uint8_t state;
uint8_t methods;
uint8_t cmd;
uint8_t atyp;
uint8_t userlen;
uint8_t passlen;
uint16_t dport;
uint8_t username[257];
uint8_t password[257];
uint8_t daddr[257]; /* TODO(bnoordhuis) Merge with username/password. */
} s5_ctx;
void s5_init(s5_ctx *ctx);
s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size);
/* Only call after s5_parse() has returned s5_want_auth_method. */
unsigned int s5_auth_methods(const s5_ctx *cx);
/* Call after s5_parse() has returned s5_want_auth_method. */
int s5_select_auth(s5_ctx *cx, s5_auth_method method);
const char *s5_strerror(s5_err err);
#endif /* S5_H_ */

241
deps/uv/samples/socks5-proxy/server.c

@ -0,0 +1,241 @@
/* Copyright StrongLoop, Inc. 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 "defs.h"
#include <netinet/in.h> /* INET6_ADDRSTRLEN */
#include <stdlib.h>
#include <string.h>
#ifndef INET6_ADDRSTRLEN
# define INET6_ADDRSTRLEN 63
#endif
typedef struct {
uv_getaddrinfo_t getaddrinfo_req;
server_config config;
server_ctx *servers;
uv_loop_t *loop;
} server_state;
static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *ai);
static void on_connection(uv_stream_t *server, int status);
int server_run(const server_config *cf, uv_loop_t *loop) {
struct addrinfo hints;
server_state state;
int err;
memset(&state, 0, sizeof(state));
state.servers = NULL;
state.config = *cf;
state.loop = loop;
/* Resolve the address of the interface that we should bind to.
* The getaddrinfo callback starts the server and everything else.
*/
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
err = uv_getaddrinfo(loop,
&state.getaddrinfo_req,
do_bind,
cf->bind_host,
NULL,
&hints);
if (err != 0) {
pr_err("getaddrinfo: %s", uv_strerror(err));
return err;
}
/* Start the event loop. Control continues in do_bind(). */
if (uv_run(loop, UV_RUN_DEFAULT)) {
abort();
}
/* Please Valgrind. */
uv_loop_delete(loop);
free(state.servers);
return 0;
}
/* Bind a server to each address that getaddrinfo() reported. */
static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) {
char addrbuf[INET6_ADDRSTRLEN + 1];
unsigned int ipv4_naddrs;
unsigned int ipv6_naddrs;
server_state *state;
server_config *cf;
struct addrinfo *ai;
const void *addrv;
const char *what;
uv_loop_t *loop;
server_ctx *sx;
unsigned int n;
int err;
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} s;
state = CONTAINER_OF(req, server_state, getaddrinfo_req);
loop = state->loop;
cf = &state->config;
if (status < 0) {
pr_err("getaddrinfo(\"%s\"): %s", cf->bind_host, uv_strerror(status));
uv_freeaddrinfo(addrs);
return;
}
ipv4_naddrs = 0;
ipv6_naddrs = 0;
for (ai = addrs; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family == AF_INET) {
ipv4_naddrs += 1;
} else if (ai->ai_family == AF_INET6) {
ipv6_naddrs += 1;
}
}
if (ipv4_naddrs == 0 && ipv6_naddrs == 0) {
pr_err("%s has no IPv4/6 addresses", cf->bind_host);
uv_freeaddrinfo(addrs);
return;
}
state->servers =
xmalloc((ipv4_naddrs + ipv6_naddrs) * sizeof(state->servers[0]));
n = 0;
for (ai = addrs; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
continue;
}
if (ai->ai_family == AF_INET) {
s.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
s.addr4.sin_port = htons(cf->bind_port);
addrv = &s.addr4.sin_addr;
} else if (ai->ai_family == AF_INET6) {
s.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
s.addr6.sin6_port = htons(cf->bind_port);
addrv = &s.addr6.sin6_addr;
} else {
UNREACHABLE();
}
if (uv_inet_ntop(s.addr.sa_family, addrv, addrbuf, sizeof(addrbuf))) {
UNREACHABLE();
}
sx = state->servers + n;
sx->loop = loop;
sx->idle_timeout = state->config.idle_timeout;
CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle));
what = "uv_tcp_bind";
err = uv_tcp_bind(&sx->tcp_handle, &s.addr);
if (err == 0) {
what = "uv_listen";
err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection);
}
if (err != 0) {
pr_err("%s(\"%s:%hu\"): %s",
what,
addrbuf,
cf->bind_port,
uv_strerror(err));
while (n > 0) {
n -= 1;
uv_close((uv_handle_t *) (state->servers + n), NULL);
}
break;
}
pr_info("listening on %s:%hu", addrbuf, cf->bind_port);
n += 1;
}
uv_freeaddrinfo(addrs);
}
static void on_connection(uv_stream_t *server, int status) {
server_ctx *sx;
client_ctx *cx;
CHECK(status == 0);
sx = CONTAINER_OF(server, server_ctx, tcp_handle);
cx = xmalloc(sizeof(*cx));
CHECK(0 == uv_tcp_init(sx->loop, &cx->incoming.handle.tcp));
CHECK(0 == uv_accept(server, &cx->incoming.handle.stream));
client_finish_init(sx, cx);
}
int can_auth_none(const server_ctx *sx, const client_ctx *cx) {
return 1;
}
int can_auth_passwd(const server_ctx *sx, const client_ctx *cx) {
return 0;
}
int can_access(const server_ctx *sx,
const client_ctx *cx,
const struct sockaddr *addr) {
const struct sockaddr_in6 *addr6;
const struct sockaddr_in *addr4;
const uint32_t *p;
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
/* TODO(bnoordhuis) Implement proper access checks. For now, just reject
* traffic to localhost.
*/
if (addr->sa_family == AF_INET) {
addr4 = (const struct sockaddr_in *) addr;
d = ntohl(addr4->sin_addr.s_addr);
return (d >> 24) != 0x7F;
}
if (addr->sa_family == AF_INET6) {
addr6 = (const struct sockaddr_in6 *) addr;
p = (const uint32_t *) &addr6->sin6_addr.s6_addr;
a = ntohl(p[0]);
b = ntohl(p[1]);
c = ntohl(p[2]);
d = ntohl(p[3]);
if (a == 0 && b == 0 && c == 0 && d == 1) {
return 0; /* "::1" style address. */
}
if (a == 0 && b == 0 && c == 0xFFFF && (d >> 24) == 0x7F) {
return 0; /* "::ffff:127.x.x.x" style address. */
}
return 1;
}
return 0;
}

72
deps/uv/samples/socks5-proxy/util.c

@ -0,0 +1,72 @@
/* Copyright StrongLoop, Inc. 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 "defs.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
static void pr_do(FILE *stream,
const char *label,
const char *fmt,
va_list ap);
void *xmalloc(size_t size) {
void *ptr;
ptr = malloc(size);
if (ptr == NULL) {
pr_err("out of memory, need %lu bytes", (unsigned long) size);
exit(1);
}
return ptr;
}
void pr_info(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pr_do(stdout, "info", fmt, ap);
va_end(ap);
}
void pr_warn(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pr_do(stderr, "warn", fmt, ap);
va_end(ap);
}
void pr_err(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pr_do(stderr, "error", fmt, ap);
va_end(ap);
}
static void pr_do(FILE *stream,
const char *label,
const char *fmt,
va_list ap) {
char fmtbuf[1024];
vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
fprintf(stream, "%s:%s: %s\n", _getprogname(), label, fmtbuf);
}

12
deps/uv/src/queue.h

@ -19,20 +19,20 @@
typedef void *QUEUE[2]; typedef void *QUEUE[2];
/* Private macros. */ /* Private macros. */
#define QUEUE_NEXT(q) ((*(q))[0]) #define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
#define QUEUE_PREV(q) ((*(q))[1]) #define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT((QUEUE *) QUEUE_PREV(q))) #define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV((QUEUE *) QUEUE_NEXT(q))) #define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
/* Public macros. */ /* Public macros. */
#define QUEUE_DATA(ptr, type, field) \ #define QUEUE_DATA(ptr, type, field) \
((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field))) ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
#define QUEUE_FOREACH(q, h) \ #define QUEUE_FOREACH(q, h) \
for ((q) = (QUEUE *) (*(h))[0]; (q) != (h); (q) = (QUEUE *) (*(q))[0]) for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
#define QUEUE_EMPTY(q) \ #define QUEUE_EMPTY(q) \
(QUEUE_NEXT(q) == (q)) ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
#define QUEUE_HEAD(q) \ #define QUEUE_HEAD(q) \
(QUEUE_NEXT(q)) (QUEUE_NEXT(q))

2
deps/uv/src/unix/aix.c

@ -45,7 +45,7 @@
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/procfs.h> #include <sys/procfs.h>
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
uint64_t G = 1000000000; uint64_t G = 1000000000;
timebasestruct_t t; timebasestruct_t t;
read_wall_time(&t, TIMEBASE_SZ); read_wall_time(&t, TIMEBASE_SZ);

62
deps/uv/src/unix/core.c

@ -73,7 +73,7 @@ STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
uint64_t uv_hrtime(void) { uint64_t uv_hrtime(void) {
return uv__hrtime(); return uv__hrtime(UV_CLOCK_PRECISE);
} }
@ -542,6 +542,44 @@ int uv__dup(int fd) {
} }
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
struct cmsghdr* cmsg;
ssize_t rc;
int* pfd;
int* end;
#if defined(__linux__)
static int no_msg_cmsg_cloexec;
if (no_msg_cmsg_cloexec == 0) {
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
if (rc != -1)
return rc;
if (errno != EINVAL)
return -errno;
rc = recvmsg(fd, msg, flags);
if (rc == -1)
return -errno;
no_msg_cmsg_cloexec = 1;
} else {
rc = recvmsg(fd, msg, flags);
}
#else
rc = recvmsg(fd, msg, flags);
#endif
if (rc == -1)
return -errno;
if (msg->msg_controllen == 0)
return rc;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
if (cmsg->cmsg_type == SCM_RIGHTS)
for (pfd = (int*) CMSG_DATA(cmsg),
end = (int*) ((char*) cmsg + cmsg->cmsg_len);
pfd < end;
pfd += 1)
uv__cloexec(*pfd, 1);
return rc;
}
int uv_cwd(char* buffer, size_t size) { int uv_cwd(char* buffer, size_t size) {
if (buffer == NULL) if (buffer == NULL)
return -EINVAL; return -EINVAL;
@ -604,20 +642,33 @@ static unsigned int next_power_of_two(unsigned int val) {
static void maybe_resize(uv_loop_t* loop, unsigned int len) { static void maybe_resize(uv_loop_t* loop, unsigned int len) {
uv__io_t** watchers; uv__io_t** watchers;
void* fake_watcher_list;
void* fake_watcher_count;
unsigned int nwatchers; unsigned int nwatchers;
unsigned int i; unsigned int i;
if (len <= loop->nwatchers) if (len <= loop->nwatchers)
return; return;
nwatchers = next_power_of_two(len); /* Preserve fake watcher list and count at the end of the watchers */
watchers = realloc(loop->watchers, nwatchers * sizeof(loop->watchers[0])); if (loop->watchers != NULL) {
fake_watcher_list = loop->watchers[loop->nwatchers];
fake_watcher_count = loop->watchers[loop->nwatchers + 1];
} else {
fake_watcher_list = NULL;
fake_watcher_count = NULL;
}
nwatchers = next_power_of_two(len + 2) - 2;
watchers = realloc(loop->watchers,
(nwatchers + 2) * sizeof(loop->watchers[0]));
if (watchers == NULL) if (watchers == NULL)
abort(); abort();
for (i = loop->nwatchers; i < nwatchers; i++) for (i = loop->nwatchers; i < nwatchers; i++)
watchers[i] = NULL; watchers[i] = NULL;
watchers[nwatchers] = fake_watcher_list;
watchers[nwatchers + 1] = fake_watcher_count;
loop->watchers = watchers; loop->watchers = watchers;
loop->nwatchers = nwatchers; loop->nwatchers = nwatchers;
@ -709,6 +760,9 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_close(uv_loop_t* loop, uv__io_t* w) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
QUEUE_REMOVE(&w->pending_queue); QUEUE_REMOVE(&w->pending_queue);
/* Remove stale events for this file descriptor */
uv__platform_invalidate_fd(loop, w->fd);
} }

2
deps/uv/src/unix/darwin.c

@ -52,7 +52,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
mach_timebase_info_data_t info; mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS) if (mach_timebase_info(&info) != KERN_SUCCESS)

2
deps/uv/src/unix/freebsd.c

@ -67,7 +67,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);

2
deps/uv/src/unix/fs.c

@ -170,6 +170,8 @@ skip:
#elif defined(__APPLE__) \ #elif defined(__APPLE__) \
|| defined(__DragonFly__) \ || defined(__DragonFly__) \
|| defined(__FreeBSD__) \ || defined(__FreeBSD__) \
|| defined(__NetBSD__) \
|| defined(__OpenBSD__) \
|| defined(__sun) || defined(__sun)
struct timeval tv[2]; struct timeval tv[2];
tv[0].tv_sec = req->atime; tv[0].tv_sec = req->atime;

203
deps/uv/src/unix/fsevents.c

@ -73,28 +73,28 @@ typedef struct uv__fsevents_event_s uv__fsevents_event_t;
typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
struct uv__cf_loop_state_s {
CFRunLoopRef loop;
CFRunLoopSourceRef signal_source;
int fsevent_need_reschedule;
FSEventStreamRef fsevent_stream;
uv_sem_t fsevent_sem;
uv_mutex_t fsevent_mutex;
void* fsevent_handles[2];
int fsevent_handle_count;
};
struct uv__cf_loop_signal_s { struct uv__cf_loop_signal_s {
QUEUE member; QUEUE member;
uv_fs_event_t* handle; uv_fs_event_t* handle;
}; };
struct uv__fsevents_event_s { struct uv__fsevents_event_s {
QUEUE member;
int events; int events;
void* next;
char path[1]; char path[1];
}; };
struct uv__cf_loop_state_s {
CFRunLoopRef loop;
CFRunLoopSourceRef signal_source;
int fsevent_need_reschedule;
FSEventStreamRef fsevent_stream;
uv_sem_t fsevent_sem;
uv_mutex_t fsevent_mutex;
void* fsevent_handles[2];
unsigned int fsevent_handle_count;
};
/* Forward declarations */ /* Forward declarations */
static void uv__cf_loop_cb(void* arg); static void uv__cf_loop_cb(void* arg);
static void* uv__cf_loop_runner(void* arg); static void* uv__cf_loop_runner(void* arg);
@ -120,9 +120,9 @@ static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef); static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
static void (*pCFRunLoopStop)(CFRunLoopRef); static void (*pCFRunLoopStop)(CFRunLoopRef);
static void (*pCFRunLoopWakeUp)(CFRunLoopRef); static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
const char*, CFAllocatorRef,
CFStringEncoding); const char*);
static CFStringEncoding (*pCFStringGetSystemEncoding)(void); static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
static CFStringRef (*pkCFRunLoopDefaultMode); static CFStringRef (*pkCFRunLoopDefaultMode);
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
@ -143,22 +143,36 @@ static void (*pFSEventStreamStop)(FSEventStreamRef);
#define UV__FSEVENTS_PROCESS(handle, block) \ #define UV__FSEVENTS_PROCESS(handle, block) \
do { \ do { \
QUEUE events; \
QUEUE* q; \
uv__fsevents_event_t* event; \ uv__fsevents_event_t* event; \
uv__fsevents_event_t* next; \ int err; \
uv_mutex_lock(&(handle)->cf_mutex); \ uv_mutex_lock(&(handle)->cf_mutex); \
event = (handle)->cf_event; \ /* Split-off all events and empty original queue */ \
(handle)->cf_event = NULL; \ QUEUE_INIT(&events); \
if (!QUEUE_EMPTY(&(handle)->cf_events)) { \
q = QUEUE_HEAD(&(handle)->cf_events); \
QUEUE_SPLIT(&(handle)->cf_events, q, &events); \
} \
/* Get error (if any) and zero original one */ \
err = (handle)->cf_error; \
(handle)->cf_error = 0; \
uv_mutex_unlock(&(handle)->cf_mutex); \ uv_mutex_unlock(&(handle)->cf_mutex); \
while (event != NULL) { \ /* Loop through events, deallocating each after processing */ \
/* Invoke callback */ \ while (!QUEUE_EMPTY(&events)) { \
/* Invoke block code, but only if handle wasn't closed */ \ q = QUEUE_HEAD(&events); \
if (!uv__is_closing((handle))) \ event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
QUEUE_REMOVE(q); \
/* NOTE: Checking uv__is_active() is required here, because handle \
* callback may close handle and invoking it after it will lead to \
* incorrect behaviour */ \
if (!uv__is_closing((handle)) && uv__is_active((handle))) \
block \ block \
/* Free allocated data */ \ /* Free allocated data */ \
next = event->next; \
free(event); \ free(event); \
event = next; \
} \ } \
if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
(handle)->cb((handle), NULL, 0, err); \
} while (0) } while (0)
@ -169,12 +183,28 @@ static void uv__fsevents_cb(uv_async_t* cb, int status) {
handle = cb->data; handle = cb->data;
UV__FSEVENTS_PROCESS(handle, { UV__FSEVENTS_PROCESS(handle, {
if (handle->event_watcher.fd != -1) handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
}); });
}
/* Runs in CF thread, pushed event into handle's event list */
static void uv__fsevents_push_event(uv_fs_event_t* handle,
QUEUE* events,
int err) {
assert(events != NULL || err != 0);
uv_mutex_lock(&handle->cf_mutex);
/* Concatenate two queues */
if (events != NULL)
QUEUE_ADD(&handle->cf_events, events);
if (!uv__is_closing(handle) && handle->event_watcher.fd == -1) /* Propagate error */
uv__fsevents_close(handle); if (err != 0)
handle->cf_error = err;
uv_mutex_unlock(&handle->cf_mutex);
uv_async_send(handle->cf_cb);
} }
@ -195,7 +225,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
uv_loop_t* loop; uv_loop_t* loop;
uv__cf_loop_state_t* state; uv__cf_loop_state_t* state;
uv__fsevents_event_t* event; uv__fsevents_event_t* event;
uv__fsevents_event_t* tail; QUEUE head;
loop = info; loop = info;
state = loop->cf_state; state = loop->cf_state;
@ -203,9 +233,10 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
paths = eventPaths; paths = eventPaths;
/* For each handle */ /* For each handle */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) { QUEUE_FOREACH(q, &state->fsevent_handles) {
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member); handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
tail = NULL; QUEUE_INIT(&head);
/* Process and filter out events */ /* Process and filter out events */
for (i = 0; i < numEvents; i++) { for (i = 0; i < numEvents; i++) {
@ -260,25 +291,18 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
else else
event->events = UV_RENAME; event->events = UV_RENAME;
if (tail != NULL) QUEUE_INSERT_TAIL(&head, &event->member);
tail->next = event;
tail = event;
} }
if (tail != NULL) { if (!QUEUE_EMPTY(&head))
uv_mutex_lock(&handle->cf_mutex); uv__fsevents_push_event(handle, &head, 0);
tail->next = handle->cf_event;
handle->cf_event = tail;
uv_mutex_unlock(&handle->cf_mutex);
uv_async_send(handle->cf_cb);
}
} }
uv_mutex_unlock(&state->fsevent_mutex);
} }
/* Runs in CF thread */ /* Runs in CF thread */
static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
uv__cf_loop_state_t* state; uv__cf_loop_state_t* state;
FSEventStreamContext ctx; FSEventStreamContext ctx;
FSEventStreamRef ref; FSEventStreamRef ref;
@ -292,10 +316,21 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
ctx.release = NULL; ctx.release = NULL;
ctx.copyDescription = NULL; ctx.copyDescription = NULL;
latency = 0.15; latency = 0.05;
/* Set appropriate flags */ /* Explanation of selected flags:
flags = kFSEventStreamCreateFlagFileEvents; * 1. NoDefer - without this flag, events that are happening continuously
* (i.e. each event is happening after time interval less than `latency`,
* counted from previous event), will be deferred and passed to callback
* once they'll either fill whole OS buffer, or when this continuous stream
* will stop (i.e. there'll be delay between events, bigger than
* `latency`).
* Specifying this flag will invoke callback after `latency` time passed
* since event.
* 2. FileEvents - fire callback for file changes too (by default it is firing
* it only for directory changes).
*/
flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
/* /*
* NOTE: It might sound like a good idea to remember last seen StreamEventId, * NOTE: It might sound like a good idea to remember last seen StreamEventId,
@ -316,10 +351,14 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
pFSEventStreamScheduleWithRunLoop(ref, pFSEventStreamScheduleWithRunLoop(ref,
state->loop, state->loop,
*pkCFRunLoopDefaultMode); *pkCFRunLoopDefaultMode);
if (!pFSEventStreamStart(ref)) if (!pFSEventStreamStart(ref)) {
abort(); pFSEventStreamInvalidate(ref);
pFSEventStreamRelease(ref);
return -EMFILE;
}
state->fsevent_stream = ref; state->fsevent_stream = ref;
return 0;
} }
@ -352,10 +391,16 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
uv_fs_event_t* curr; uv_fs_event_t* curr;
CFArrayRef cf_paths; CFArrayRef cf_paths;
CFStringRef* paths; CFStringRef* paths;
int i; unsigned int i;
int path_count; int err;
unsigned int path_count;
state = handle->loop->cf_state; state = handle->loop->cf_state;
paths = NULL;
cf_paths = NULL;
err = 0;
/* NOTE: `i` is used in deallocation loop below */
i = 0;
/* Optimization to prevent O(n^2) time spent when starting to watch /* Optimization to prevent O(n^2) time spent when starting to watch
* many files simultaneously * many files simultaneously
@ -371,39 +416,68 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
/* Destroy previous FSEventStream */ /* Destroy previous FSEventStream */
uv__fsevents_destroy_stream(handle->loop); uv__fsevents_destroy_stream(handle->loop);
/* Any failure below will be a memory failure */
err = -ENOMEM;
/* Create list of all watched paths */ /* Create list of all watched paths */
uv_mutex_lock(&state->fsevent_mutex); uv_mutex_lock(&state->fsevent_mutex);
path_count = state->fsevent_handle_count; path_count = state->fsevent_handle_count;
if (path_count != 0) { if (path_count != 0) {
paths = malloc(sizeof(*paths) * path_count); paths = malloc(sizeof(*paths) * path_count);
if (paths == NULL) if (paths == NULL) {
abort(); uv_mutex_unlock(&state->fsevent_mutex);
goto final;
}
q = &state->fsevent_handles; q = &state->fsevent_handles;
for (i = 0; i < path_count; i++) { for (; i < path_count; i++) {
q = QUEUE_NEXT(q); q = QUEUE_NEXT(q);
assert(q != &state->fsevent_handles); assert(q != &state->fsevent_handles);
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
assert(curr->realpath != NULL); assert(curr->realpath != NULL);
paths[i] = pCFStringCreateWithCString(NULL, paths[i] =
curr->realpath, pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
pCFStringGetSystemEncoding()); if (paths[i] == NULL) {
if (paths[i] == NULL) uv_mutex_unlock(&state->fsevent_mutex);
abort(); goto final;
}
} }
} }
uv_mutex_unlock(&state->fsevent_mutex); uv_mutex_unlock(&state->fsevent_mutex);
err = 0;
if (path_count != 0) { if (path_count != 0) {
/* Create new FSEventStream */ /* Create new FSEventStream */
cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
if (cf_paths == NULL) if (cf_paths == NULL) {
abort(); err = -ENOMEM;
uv__fsevents_create_stream(handle->loop, cf_paths); goto final;
}
err = uv__fsevents_create_stream(handle->loop, cf_paths);
} }
final: final:
/* Deallocate all paths in case of failure */
if (err != 0) {
if (cf_paths == NULL) {
while (i != 0)
pCFRelease(paths[--i]);
free(paths);
} else {
/* CFArray takes ownership of both strings and original C-array */
pCFRelease(cf_paths);
}
/* Broadcast error to all handles */
uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
uv__fsevents_push_event(curr, NULL, err);
}
uv_mutex_unlock(&state->fsevent_mutex);
}
/* /*
* Main thread will block until the removal of handle from the list, * Main thread will block until the removal of handle from the list,
* we must tell it when we're ready. * we must tell it when we're ready.
@ -464,7 +538,7 @@ static int uv__fsevents_global_init(void) {
V(core_foundation_handle, CFRunLoopSourceSignal); V(core_foundation_handle, CFRunLoopSourceSignal);
V(core_foundation_handle, CFRunLoopStop); V(core_foundation_handle, CFRunLoopStop);
V(core_foundation_handle, CFRunLoopWakeUp); V(core_foundation_handle, CFRunLoopWakeUp);
V(core_foundation_handle, CFStringCreateWithCString); V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
V(core_foundation_handle, CFStringGetSystemEncoding); V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, kCFRunLoopDefaultMode); V(core_foundation_handle, kCFRunLoopDefaultMode);
V(core_services_handle, FSEventStreamCreate); V(core_services_handle, FSEventStreamCreate);
@ -722,8 +796,9 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
return -errno; return -errno;
handle->realpath_len = strlen(handle->realpath); handle->realpath_len = strlen(handle->realpath);
/* Initialize singly-linked list */ /* Initialize event queue */
handle->cf_event = NULL; QUEUE_INIT(&handle->cf_events);
handle->cf_error = 0;
/* /*
* Events will occur in other thread. * Events will occur in other thread.

14
deps/uv/src/unix/internal.h

@ -128,12 +128,18 @@ enum {
UV_TCP_SINGLE_ACCEPT = 0x1000 /* Only accept() when idle. */ UV_TCP_SINGLE_ACCEPT = 0x1000 /* Only accept() when idle. */
}; };
typedef enum {
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
} uv_clocktype_t;
/* core */ /* core */
int uv__nonblock(int fd, int set); int uv__nonblock(int fd, int set);
int uv__close(int fd); int uv__close(int fd);
int uv__cloexec(int fd, int set); int uv__cloexec(int fd, int set);
int uv__socket(int domain, int type, int protocol); int uv__socket(int domain, int type, int protocol);
int uv__dup(int fd); int uv__dup(int fd);
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
void uv__make_close_pending(uv_handle_t* handle); void uv__make_close_pending(uv_handle_t* handle);
void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
@ -191,10 +197,11 @@ void uv__work_submit(uv_loop_t* loop,
void uv__work_done(uv_async_t* handle, int status); void uv__work_done(uv_async_t* handle, int status);
/* platform specific */ /* platform specific */
uint64_t uv__hrtime(void); uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop); int uv__kqueue_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop, int default_loop); int uv__platform_loop_init(uv_loop_t* loop, int default_loop);
void uv__platform_loop_delete(uv_loop_t* loop); void uv__platform_loop_delete(uv_loop_t* loop);
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
/* various */ /* various */
void uv__async_close(uv_async_t* handle); void uv__async_close(uv_async_t* handle);
@ -236,6 +243,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop);
/* OSX < 10.7 has no file events, polyfill them */ /* OSX < 10.7 has no file events, polyfill them */
#ifndef MAC_OS_X_VERSION_10_7 #ifndef MAC_OS_X_VERSION_10_7
static const int kFSEventStreamCreateFlagNoDefer = 0x00000002;
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
static const int kFSEventStreamEventFlagItemCreated = 0x00000100; static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
@ -263,7 +271,9 @@ UV_UNUSED(static void uv__req_init(uv_loop_t* loop,
uv__req_init((loop), (uv_req_t*)(req), (type)) uv__req_init((loop), (uv_req_t*)(req), (type))
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
loop->time = uv__hrtime() / 1000000; /* Use a fast time source if available. We only need millisecond precision.
*/
loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
} }
UV_UNUSED(static char* uv__basename_r(const char* path)) { UV_UNUSED(static char* uv__basename_r(const char* path)) {

32
deps/uv/src/unix/kqueue.c

@ -161,11 +161,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents = 0; nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
ev = events + i; ev = events + i;
fd = ev->ident; fd = ev->ident;
w = loop->watchers[fd]; w = loop->watchers[fd];
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
if (w == NULL) { if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it. */ /* File descriptor that we've stopped watching, disarm it. */
/* TODO batch up */ /* TODO batch up */
@ -190,7 +197,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
revents = 0; revents = 0;
if (ev->filter == EVFILT_READ) { if (ev->filter == EVFILT_READ) {
if (w->events & UV__POLLIN) { if (w->pevents & UV__POLLIN) {
revents |= UV__POLLIN; revents |= UV__POLLIN;
w->rcount = ev->data; w->rcount = ev->data;
} else { } else {
@ -204,7 +211,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
} }
if (ev->filter == EVFILT_WRITE) { if (ev->filter == EVFILT_WRITE) {
if (w->events & UV__POLLOUT) { if (w->pevents & UV__POLLOUT) {
revents |= UV__POLLOUT; revents |= UV__POLLOUT;
w->wcount = ev->data; w->wcount = ev->data;
} else { } else {
@ -226,6 +233,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
w->cb(loop, w, revents); w->cb(loop, w, revents);
nevents++; nevents++;
} }
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) { if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) {
@ -254,6 +263,25 @@ update_timeout:
} }
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct kevent* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct kevent*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].ident == fd)
events[i].ident = -1;
}
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) { static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
uv_fs_event_t* handle; uv_fs_event_t* handle;
struct kevent ev; struct kevent ev;

99
deps/uv/src/unix/linux-core.c

@ -52,8 +52,10 @@
# include <linux/if_packet.h> # include <linux/if_packet.h>
#endif #endif
#undef NANOSEC /* Available from 2.6.32 onwards. */
#define NANOSEC ((uint64_t) 1e9) #ifndef CLOCK_MONOTONIC_COARSE
# define CLOCK_MONOTONIC_COARSE 6
#endif
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't /* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
* include that file because it conflicts with <time.h>. We'll just have to * include that file because it conflicts with <time.h>. We'll just have to
@ -103,6 +105,25 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct uv__epoll_event* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].data == fd)
events[i].data = -1;
}
void uv__io_poll(uv_loop_t* loop, int timeout) { void uv__io_poll(uv_loop_t* loop, int timeout) {
struct uv__epoll_event events[1024]; struct uv__epoll_event events[1024];
struct uv__epoll_event* pe; struct uv__epoll_event* pe;
@ -195,10 +216,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents = 0; nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
pe = events + i; pe = events + i;
fd = pe->data; fd = pe->data;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0); assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers); assert((unsigned) fd < loop->nwatchers);
@ -214,9 +242,38 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
continue; continue;
} }
w->cb(loop, w, pe->events); /* Give users only events they're interested in. Prevents spurious
nevents++; * callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP;
/* Work around an epoll quirk where it sometimes reports just the
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
* move forward, we merge in the read/write events that the watcher
* is interested in; uv__read() and uv__write() will then deal with
* the error or hangup in the usual fashion.
*
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
* reads the available data, calls uv_read_stop(), then sometime later
* calls uv_read_start() again. By then, libuv has forgotten about the
* hangup and the kernel won't report EPOLLIN again because there's
* nothing left to read. If anything, libuv is to blame here. The
* current hack is just a quick bandaid; to properly fix it, libuv
* needs to remember the error/hangup event. We should get that for
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP)
pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT);
if (pe->events != 0) {
w->cb(loop, w, pe->events);
nevents++;
}
} }
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) { if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) {
@ -245,10 +302,36 @@ update_timeout:
} }
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts; static clock_t fast_clock_id = -1;
clock_gettime(CLOCK_MONOTONIC, &ts); struct timespec t;
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); clock_t clock_id;
/* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
* millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
* serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
* decide to make a costly system call.
*/
/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
* when it has microsecond granularity or better (unlikely).
*/
if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
t.tv_nsec <= 1 * 1000 * 1000) {
fast_clock_id = CLOCK_MONOTONIC_COARSE;
} else {
fast_clock_id = CLOCK_MONOTONIC;
}
}
clock_id = CLOCK_MONOTONIC;
if (type == UV_CLOCK_FAST)
clock_id = fast_clock_id;
if (clock_gettime(clock_id, &t))
return 0; /* Not really possible. */
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
} }

2
deps/uv/src/unix/loop.c

@ -96,7 +96,7 @@ static int uv__loop_init(uv_loop_t* loop, int default_loop) {
QUEUE_INIT(&loop->watcher_queue); QUEUE_INIT(&loop->watcher_queue);
loop->closing_handles = NULL; loop->closing_handles = NULL;
loop->time = uv__hrtime() / 1000000; uv__update_time(loop);
uv__async_init(&loop->async_watcher); uv__async_init(&loop->async_watcher);
loop->signal_pipefd[0] = -1; loop->signal_pipefd[0] = -1;
loop->signal_pipefd[1] = -1; loop->signal_pipefd[1] = -1;

2
deps/uv/src/unix/netbsd.c

@ -57,7 +57,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);

2
deps/uv/src/unix/openbsd.c

@ -56,7 +56,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);

6
deps/uv/src/unix/pipe.c

@ -72,7 +72,8 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
sockfd = err; sockfd = err;
memset(&saddr, 0, sizeof saddr); memset(&saddr, 0, sizeof saddr);
uv_strlcpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path)); strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
saddr.sun_family = AF_UNIX; saddr.sun_family = AF_UNIX;
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
@ -167,7 +168,8 @@ void uv_pipe_connect(uv_connect_t* req,
} }
memset(&saddr, 0, sizeof saddr); memset(&saddr, 0, sizeof saddr);
uv_strlcpy(saddr.sun_path, name, sizeof(saddr.sun_path)); strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
saddr.sun_family = AF_UNIX; saddr.sun_family = AF_UNIX;
do { do {

21
deps/uv/src/unix/process.c

@ -109,9 +109,6 @@ static void uv__chld(uv_signal_t* handle, int signum) {
if (WIFSIGNALED(process->status)) if (WIFSIGNALED(process->status))
term_signal = WTERMSIG(process->status); term_signal = WTERMSIG(process->status);
if (process->errorno != 0)
exit_status = process->errorno; /* execve() failed */
process->exit_cb(process, exit_status, term_signal); process->exit_cb(process, exit_status, term_signal);
} }
} }
@ -359,6 +356,7 @@ int uv_spawn(uv_loop_t* loop,
ssize_t r; ssize_t r;
pid_t pid; pid_t pid;
int err; int err;
int exec_errorno;
int i; int i;
assert(options->file != NULL); assert(options->file != NULL);
@ -434,14 +432,14 @@ int uv_spawn(uv_loop_t* loop,
uv__close(signal_pipe[1]); uv__close(signal_pipe[1]);
process->status = 0; process->status = 0;
process->errorno = 0; exec_errorno = 0;
do do
r = read(signal_pipe[0], &process->errorno, sizeof(process->errorno)); r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
while (r == -1 && errno == EINTR); while (r == -1 && errno == EINTR);
if (r == 0) if (r == 0)
; /* okay, EOF */ ; /* okay, EOF */
else if (r == sizeof(process->errorno)) else if (r == sizeof(exec_errorno))
; /* okay, read errorno */ ; /* okay, read errorno */
else if (r == -1 && errno == EPIPE) else if (r == -1 && errno == EPIPE)
; /* okay, got EPIPE */ ; /* okay, got EPIPE */
@ -461,15 +459,18 @@ int uv_spawn(uv_loop_t* loop,
goto error; goto error;
} }
q = uv__process_queue(loop, pid); /* Only activate this handle if exec() happened successfully */
QUEUE_INSERT_TAIL(q, &process->queue); if (exec_errorno == 0) {
q = uv__process_queue(loop, pid);
QUEUE_INSERT_TAIL(q, &process->queue);
uv__handle_start(process);
}
process->pid = pid; process->pid = pid;
process->exit_cb = options->exit_cb; process->exit_cb = options->exit_cb;
uv__handle_start(process);
free(pipes); free(pipes);
return 0; return exec_errorno;
error: error:
if (pipes != NULL) { if (pipes != NULL) {

4
deps/uv/src/unix/stream.c

@ -298,7 +298,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
kq = kqueue(); kq = kqueue();
if (kq == -1) { if (kq == -1) {
fprintf(stderr, "(libuv) Failed to create kqueue (%d)\n", errno); perror("(libuv) kqueue()");
return -errno; return -errno;
} }
@ -1007,7 +1007,7 @@ static void uv__read(uv_stream_t* stream) {
msg.msg_control = (void*) cmsg_space; msg.msg_control = (void*) cmsg_space;
do { do {
nread = recvmsg(uv__stream_fd(stream), &msg, 0); nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
} }
while (nread < 0 && errno == EINTR); while (nread < 0 && errno == EINTR);
} }

30
deps/uv/src/unix/sunos.c

@ -97,6 +97,25 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
} }
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct port_event* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct port_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].portev_object == fd)
events[i].portev_object = -1;
}
void uv__io_poll(uv_loop_t* loop, int timeout) { void uv__io_poll(uv_loop_t* loop, int timeout) {
struct port_event events[1024]; struct port_event events[1024];
struct port_event* pe; struct port_event* pe;
@ -183,10 +202,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents = 0; nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
pe = events + i; pe = events + i;
fd = pe->portev_object; fd = pe->portev_object;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0); assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers); assert((unsigned) fd < loop->nwatchers);
@ -206,6 +232,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
} }
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) { if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) {
@ -239,7 +267,7 @@ update_timeout:
} }
uint64_t uv__hrtime(void) { uint64_t uv__hrtime(uv_clocktype_t type) {
return gethrtime(); return gethrtime();
} }

2
deps/uv/src/unix/thread.c

@ -335,7 +335,7 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
ts.tv_nsec = timeout % NANOSEC; ts.tv_nsec = timeout % NANOSEC;
r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
#else #else
timeout += uv__hrtime(); timeout += uv__hrtime(UV_CLOCK_PRECISE);
ts.tv_sec = timeout / NANOSEC; ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC; ts.tv_nsec = timeout % NANOSEC;
#if defined(__ANDROID__) #if defined(__ANDROID__)

34
deps/uv/src/uv-common.c

@ -66,40 +66,6 @@ size_t uv_req_size(uv_req_type type) {
#undef XX #undef XX
size_t uv_strlcpy(char* dst, const char* src, size_t size) {
size_t n;
if (size == 0)
return 0;
for (n = 0; n < (size - 1) && *src != '\0'; n++)
*dst++ = *src++;
*dst = '\0';
return n;
}
size_t uv_strlcat(char* dst, const char* src, size_t size) {
size_t n;
if (size == 0)
return 0;
for (n = 0; n < size && *dst != '\0'; n++, dst++);
if (n == size)
return n;
while (n < (size - 1) && *src != '\0')
n++, *dst++ = *src++;
*dst = '\0';
return n;
}
uv_buf_t uv_buf_init(char* base, unsigned int len) { uv_buf_t uv_buf_init(char* base, unsigned int len) {
uv_buf_t buf; uv_buf_t buf;

2
deps/uv/src/version.c

@ -31,7 +31,7 @@
#define UV_VERSION_MAJOR 0 #define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11 #define UV_VERSION_MINOR 11
#define UV_VERSION_PATCH 14 #define UV_VERSION_PATCH 15
#define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_IS_RELEASE 1

6
deps/uv/src/win/fs.c

@ -738,11 +738,7 @@ void fs__readdir(uv_fs_t* req) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
} }
#ifdef _CRT_NON_CONFORMING_SWPRINTFS _snwprintf(path2, len + 3, fmt, pathw);
swprintf(path2, fmt, pathw);
#else
swprintf(path2, len + 3, fmt, pathw);
#endif
dir = FindFirstFileW(path2, &ent); dir = FindFirstFileW(path2, &ent);
free(path2); free(path2);

23
deps/uv/src/win/process.c

@ -127,7 +127,6 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
handle->exit_cb = NULL; handle->exit_cb = NULL;
handle->pid = 0; handle->pid = 0;
handle->spawn_error = 0;
handle->exit_signal = 0; handle->exit_signal = 0;
handle->wait_handle = INVALID_HANDLE_VALUE; handle->wait_handle = INVALID_HANDLE_VALUE;
handle->process_handle = INVALID_HANDLE_VALUE; handle->process_handle = INVALID_HANDLE_VALUE;
@ -752,10 +751,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
/* callback.*/ /* callback.*/
uv__handle_stop(handle); uv__handle_stop(handle);
if (handle->spawn_error) { if (GetExitCodeProcess(handle->process_handle, &status)) {
/* Spawning failed. */
exit_code = uv_translate_sys_error(handle->spawn_error);
} else if (GetExitCodeProcess(handle->process_handle, &status)) {
exit_code = status; exit_code = status;
} else { } else {
/* Unable to to obtain the exit code. This should never happen. */ /* Unable to to obtain the exit code. This should never happen. */
@ -1025,25 +1021,20 @@ int uv_spawn(uv_loop_t* loop,
free(env); free(env);
free(path); free(path);
process->spawn_error = err;
if (process->child_stdio_buffer != NULL) { if (process->child_stdio_buffer != NULL) {
/* Clean up child stdio handles. */ /* Clean up child stdio handles. */
uv__stdio_destroy(process->child_stdio_buffer); uv__stdio_destroy(process->child_stdio_buffer);
process->child_stdio_buffer = NULL; process->child_stdio_buffer = NULL;
} }
/* Make the handle active. It will remain active until the exit callback */ /* Make the handle active, but only if an error didn't happen. It will */
/* is made or the handle is closed, whichever happens first. */ /* remain active until the exit callback is made or the handle is closed, */
uv__handle_start(process); /* whichever happens first. */
if (err == 0) {
/* If an error happened, queue the exit req. */ uv__handle_start(process);
if (err) {
process->exit_cb_pending = 1;
uv_insert_pending_req(loop, (uv_req_t*) &process->exit_req);
} }
return 0; return err;
/* This code path is taken when we run into an error that we want to */ /* This code path is taken when we run into an error that we want to */
/* report immediately. */ /* report immediately. */

23
deps/uv/test/task.h

@ -32,6 +32,11 @@
# include <stdint.h> # include <stdint.h>
#endif #endif
#if !defined(_WIN32)
# include <sys/time.h>
# include <sys/resource.h> /* setrlimit() */
#endif
#define TEST_PORT 9123 #define TEST_PORT 9123
#define TEST_PORT_2 9124 #define TEST_PORT_2 9124
@ -153,6 +158,24 @@ enum test_status {
return TEST_SKIP; \ return TEST_SKIP; \
} while (0) } while (0)
#if !defined(_WIN32)
# define TEST_FILE_LIMIT(num) \
do { \
struct rlimit lim; \
lim.rlim_cur = (num); \
lim.rlim_max = lim.rlim_cur; \
if (setrlimit(RLIMIT_NOFILE, &lim)) \
RETURN_SKIP("File descriptor limit too low."); \
} while (0)
#else /* defined(_WIN32) */
# define TEST_FILE_LIMIT(num) do {} while (0)
#endif
#if defined _WIN32 && ! defined __GNUC__ #if defined _WIN32 && ! defined __GNUC__
#include <stdarg.h> #include <stdarg.h>

77
deps/uv/test/test-close-fd.c

@ -0,0 +1,77 @@
/* 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.
*/
#if !defined(_WIN32)
#include "uv.h"
#include "task.h"
#include <fcntl.h>
#include <unistd.h>
static unsigned int read_cb_called;
static void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
static char slab[1];
buf->base = slab;
buf->len = sizeof(slab);
}
static void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
switch (++read_cb_called) {
case 1:
ASSERT(nread == 1);
uv_read_stop(handle);
break;
case 2:
ASSERT(nread == UV_EOF);
uv_close((uv_handle_t *) handle, NULL);
break;
default:
ASSERT(!"read_cb_called > 2");
}
}
TEST_IMPL(close_fd) {
uv_pipe_t pipe_handle;
int fd[2];
ASSERT(0 == pipe(fd));
ASSERT(0 == fcntl(fd[0], F_SETFL, O_NONBLOCK));
ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
ASSERT(1 == write(fd[1], "", 1));
ASSERT(0 == close(fd[1]));
fd[1] = -1;
ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(1 == read_cb_called);
ASSERT(0 == uv_is_active((const uv_handle_t *) &pipe_handle));
ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(2 == read_cb_called);
ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle));
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* !defined(_WIN32) */

200
deps/uv/test/test-fs-event.c

@ -36,11 +36,21 @@
#endif #endif
static uv_fs_event_t fs_event; static uv_fs_event_t fs_event;
static const char file_prefix[] = "fsevent-";
static uv_timer_t timer; static uv_timer_t timer;
static int timer_cb_called = 0; static int timer_cb_called;
static int close_cb_called = 0; static int close_cb_called;
static int fs_event_cb_called = 0; static const int fs_event_file_count = 128;
static int timer_cb_touch_called = 0; static int fs_event_created;
static int fs_event_cb_called;
#if defined(PATH_MAX)
static char fs_event_filename[PATH_MAX];
#else
static char fs_event_filename[1024];
#endif /* defined(PATH_MAX) */
static int timer_cb_touch_called;
static void fs_event_unlink_files(uv_timer_t* handle, int status);
static void create_dir(uv_loop_t* loop, const char* name) { static void create_dir(uv_loop_t* loop, const char* name) {
int r; int r;
@ -107,6 +117,69 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
uv_close((uv_handle_t*)handle, close_cb); uv_close((uv_handle_t*)handle, close_cb);
} }
static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
const char* filename,
int events,
int status) {
fs_event_cb_called++;
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_RENAME);
ASSERT(filename == NULL ||
strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
/* Stop watching dir when received events about all files:
* both create and close events */
if (fs_event_cb_called == 2 * fs_event_file_count) {
ASSERT(0 == uv_fs_event_stop(handle));
uv_close((uv_handle_t*) handle, close_cb);
}
}
static const char* fs_event_get_filename(int i) {
snprintf(fs_event_filename,
sizeof(fs_event_filename),
"watch_dir/%s%d",
file_prefix,
i);
return fs_event_filename;
}
static void fs_event_create_files(uv_timer_t* handle, int status) {
int i;
/* Already created all files */
if (fs_event_created == fs_event_file_count) {
uv_close((uv_handle_t*) &timer, close_cb);
return;
}
/* Create all files */
for (i = 0; i < 16; i++, fs_event_created++)
create_file(handle->loop, fs_event_get_filename(i));
/* And unlink them */
ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 50, 0));
}
void fs_event_unlink_files(uv_timer_t* handle, int status) {
int r;
int i;
/* NOTE: handle might be NULL if invoked not as timer callback */
/* Unlink all files */
for (i = 0; i < 16; i++) {
r = remove(fs_event_get_filename(i));
if (handle != NULL)
ASSERT(r == 0);
}
/* And create them again */
if (handle != NULL)
ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 50, 0));
}
static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename, static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
int events, int status) { int events, int status) {
++fs_event_cb_called; ++fs_event_cb_called;
@ -148,12 +221,6 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
} }
} }
static void timer_cb_dir(uv_timer_t* handle, int status) {
++timer_cb_called;
create_file(handle->loop, "watch_dir/file1");
uv_close((uv_handle_t*)handle, close_cb);
}
static void timer_cb_file(uv_timer_t* handle, int status) { static void timer_cb_file(uv_timer_t* handle, int status) {
++timer_cb_called; ++timer_cb_called;
@ -184,6 +251,7 @@ TEST_IMPL(fs_event_watch_dir) {
int r; int r;
/* Setup */ /* Setup */
fs_event_unlink_files(NULL, 0);
remove("watch_dir/file2"); remove("watch_dir/file2");
remove("watch_dir/file1"); remove("watch_dir/file1");
remove("watch_dir/"); remove("watch_dir/");
@ -191,20 +259,21 @@ TEST_IMPL(fs_event_watch_dir) {
r = uv_fs_event_init(loop, &fs_event); r = uv_fs_event_init(loop, &fs_event);
ASSERT(r == 0); ASSERT(r == 0);
r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_dir", 0); r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
ASSERT(r == 0); ASSERT(r == 0);
r = uv_timer_init(loop, &timer); r = uv_timer_init(loop, &timer);
ASSERT(r == 0); ASSERT(r == 0);
r = uv_timer_start(&timer, timer_cb_dir, 100, 0); r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
ASSERT(r == 0); ASSERT(r == 0);
uv_run(loop, UV_RUN_DEFAULT); uv_run(loop, UV_RUN_DEFAULT);
ASSERT(fs_event_cb_called == 1); ASSERT(fs_event_cb_called == 2 * fs_event_file_count);
ASSERT(timer_cb_called == 1); ASSERT(fs_event_created == fs_event_file_count);
ASSERT(close_cb_called == 2); ASSERT(close_cb_called == 2);
/* Cleanup */ /* Cleanup */
fs_event_unlink_files(NULL, 0);
remove("watch_dir/file2"); remove("watch_dir/file2");
remove("watch_dir/file1"); remove("watch_dir/file1");
remove("watch_dir/"); remove("watch_dir/");
@ -556,3 +625,106 @@ TEST_IMPL(fs_event_start_and_close) {
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
} }
#if defined(__APPLE__)
static int fs_event_error_reported;
static void fs_event_error_report_cb(uv_fs_event_t* handle,
const char* filename,
int events,
int status) {
if (status != 0)
fs_event_error_reported = status;
}
static void timer_cb_nop(uv_timer_t* handle, int status) {
++timer_cb_called;
uv_close((uv_handle_t*) handle, close_cb);
}
static void fs_event_error_report_close_cb(uv_handle_t* handle) {
ASSERT(handle != NULL);
close_cb_called++;
/* handle is allocated on-stack, no need to free it */
}
TEST_IMPL(fs_event_error_reporting) {
unsigned int i;
uv_loop_t* loops[1024];
uv_fs_event_t events[ARRAY_SIZE(loops)];
uv_loop_t* loop;
uv_fs_event_t* event;
TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
remove("watch_dir/");
create_dir(uv_default_loop(), "watch_dir");
/* Create a lot of loops, and start FSEventStream in each of them.
* Eventually, this should create enough streams to make FSEventStreamStart()
* fail.
*/
for (i = 0; i < ARRAY_SIZE(loops); i++) {
loop = uv_loop_new();
event = &events[i];
ASSERT(loop != NULL);
loops[i] = loop;
timer_cb_called = 0;
close_cb_called = 0;
ASSERT(0 == uv_fs_event_init(loop, event));
ASSERT(0 == uv_fs_event_start(event,
fs_event_error_report_cb,
"watch_dir",
0));
uv_unref((uv_handle_t*) event);
/* Let loop run for some time */
ASSERT(0 == uv_timer_init(loop, &timer));
ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0));
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(1 == timer_cb_called);
ASSERT(1 == close_cb_called);
if (fs_event_error_reported != 0)
break;
}
/* At least one loop should fail */
ASSERT(fs_event_error_reported == UV_EMFILE);
/* Stop and close all events, and destroy loops */
do {
loop = loops[i];
event = &events[i];
ASSERT(0 == uv_fs_event_stop(event));
uv_ref((uv_handle_t*) event);
uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
close_cb_called = 0;
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(close_cb_called == 1);
uv_loop_delete(loop);
loops[i] = NULL;
} while (i-- != 0);
remove("watch_dir/");
MAKE_VALGRIND_HAPPY();
return 0;
}
#else /* !defined(__APPLE__) */
TEST_IMPL(fs_event_error_reporting) {
/* No-op, needed only for FSEvents backend */
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif /* defined(__APPLE__) */

13
deps/uv/test/test-list.h

@ -65,6 +65,7 @@ TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_connect_timeout)
TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close_while_connecting)
TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_close)
TEST_DECLARE (tcp_close_accept)
TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_write_to_half_open_connection)
TEST_DECLARE (tcp_unexpected_read) TEST_DECLARE (tcp_unexpected_read)
@ -108,6 +109,7 @@ TEST_DECLARE (idle_starvation)
TEST_DECLARE (loop_handles) TEST_DECLARE (loop_handles)
TEST_DECLARE (get_loadavg) TEST_DECLARE (get_loadavg)
TEST_DECLARE (walk_handles) TEST_DECLARE (walk_handles)
TEST_DECLARE (watcher_cross_stop)
TEST_DECLARE (ref) TEST_DECLARE (ref)
TEST_DECLARE (idle_ref) TEST_DECLARE (idle_ref)
TEST_DECLARE (async_ref) TEST_DECLARE (async_ref)
@ -194,6 +196,7 @@ TEST_DECLARE (fs_event_immediate_close)
TEST_DECLARE (fs_event_close_with_pending_event) TEST_DECLARE (fs_event_close_with_pending_event)
TEST_DECLARE (fs_event_close_in_callback) TEST_DECLARE (fs_event_close_in_callback)
TEST_DECLARE (fs_event_start_and_close) TEST_DECLARE (fs_event_start_and_close)
TEST_DECLARE (fs_event_error_reporting)
TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_empty_dir)
TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_readdir_file)
TEST_DECLARE (fs_open_dir) TEST_DECLARE (fs_open_dir)
@ -209,8 +212,6 @@ TEST_DECLARE (thread_local_storage)
TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_mutex)
TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_create) TEST_DECLARE (thread_create)
TEST_DECLARE (strlcpy)
TEST_DECLARE (strlcat)
TEST_DECLARE (dlerror) TEST_DECLARE (dlerror)
TEST_DECLARE (poll_duplex) TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional) TEST_DECLARE (poll_unidirectional)
@ -224,6 +225,7 @@ TEST_DECLARE (listen_with_simultaneous_accepts)
TEST_DECLARE (listen_no_simultaneous_accepts) TEST_DECLARE (listen_no_simultaneous_accepts)
TEST_DECLARE (fs_stat_root) TEST_DECLARE (fs_stat_root)
#else #else
TEST_DECLARE (close_fd)
TEST_DECLARE (spawn_setuid_setgid) TEST_DECLARE (spawn_setuid_setgid)
TEST_DECLARE (we_get_signal) TEST_DECLARE (we_get_signal)
TEST_DECLARE (we_get_signals) TEST_DECLARE (we_get_signals)
@ -306,6 +308,7 @@ TASK_LIST_START
TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_connect_timeout)
TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_close)
TEST_ENTRY (tcp_close_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)
@ -396,6 +399,8 @@ TASK_LIST_START
TEST_ENTRY (loop_handles) TEST_ENTRY (loop_handles)
TEST_ENTRY (walk_handles) TEST_ENTRY (walk_handles)
TEST_ENTRY (watcher_cross_stop)
TEST_ENTRY (active) TEST_ENTRY (active)
TEST_ENTRY (embed) TEST_ENTRY (embed)
@ -452,6 +457,7 @@ TASK_LIST_START
TEST_ENTRY (listen_no_simultaneous_accepts) TEST_ENTRY (listen_no_simultaneous_accepts)
TEST_ENTRY (fs_stat_root) TEST_ENTRY (fs_stat_root)
#else #else
TEST_ENTRY (close_fd)
TEST_ENTRY (spawn_setuid_setgid) TEST_ENTRY (spawn_setuid_setgid)
TEST_ENTRY (we_get_signal) TEST_ENTRY (we_get_signal)
TEST_ENTRY (we_get_signals) TEST_ENTRY (we_get_signals)
@ -490,6 +496,7 @@ TASK_LIST_START
TEST_ENTRY (fs_event_close_with_pending_event) TEST_ENTRY (fs_event_close_with_pending_event)
TEST_ENTRY (fs_event_close_in_callback) TEST_ENTRY (fs_event_close_in_callback)
TEST_ENTRY (fs_event_start_and_close) TEST_ENTRY (fs_event_start_and_close)
TEST_ENTRY (fs_event_error_reporting)
TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_empty_dir)
TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_readdir_file)
TEST_ENTRY (fs_open_dir) TEST_ENTRY (fs_open_dir)
@ -505,8 +512,6 @@ TASK_LIST_START
TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_mutex)
TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_create) TEST_ENTRY (thread_create)
TEST_ENTRY (strlcpy)
TEST_ENTRY (strlcat)
TEST_ENTRY (dlerror) TEST_ENTRY (dlerror)
TEST_ENTRY (ip6_addr_link_local) TEST_ENTRY (ip6_addr_link_local)
#if 0 #if 0

50
deps/uv/test/test-spawn.c

@ -51,7 +51,6 @@ static void close_cb(uv_handle_t* handle) {
close_cb_called++; close_cb_called++;
} }
static void exit_cb(uv_process_t* process, static void exit_cb(uv_process_t* process,
int64_t exit_status, int64_t exit_status,
int term_signal) { int term_signal) {
@ -63,29 +62,10 @@ static void exit_cb(uv_process_t* process,
} }
static void expect(uv_process_t* process, static void fail_cb(uv_process_t* process,
int64_t exit_status, int64_t exit_status,
int term_signal, int term_signal) {
int err) { ASSERT(0 && "fail_cb called");
printf("exit_cb\n");
exit_cb_called++;
ASSERT(exit_status == err);
ASSERT(term_signal == 0);
uv_close((uv_handle_t*)process, close_cb);
}
static void exit_cb_expect_enoent(uv_process_t* process,
int64_t exit_status,
int term_signal) {
expect(process, exit_status, term_signal, UV_ENOENT);
}
static void exit_cb_expect_eperm(uv_process_t* process,
int64_t exit_status,
int term_signal) {
expect(process, exit_status, term_signal, UV_EPERM);
} }
@ -166,12 +146,12 @@ static void timer_cb(uv_timer_t* handle, int status) {
TEST_IMPL(spawn_fails) { TEST_IMPL(spawn_fails) {
init_process_options("", exit_cb_expect_enoent); init_process_options("", fail_cb);
options.file = options.args[0] = "program-that-had-better-not-exist"; options.file = options.args[0] = "program-that-had-better-not-exist";
ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
ASSERT(1 == uv_is_active((uv_handle_t*) &process)); ASSERT(UV_ENOENT == uv_spawn(uv_default_loop(), &process, &options));
ASSERT(0 == uv_is_active((uv_handle_t*) &process));
ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
ASSERT(1 == exit_cb_called);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
@ -851,19 +831,18 @@ TEST_IMPL(spawn_setuid_fails) {
ASSERT(0 == setuid(pw->pw_uid)); ASSERT(0 == setuid(pw->pw_uid));
} }
init_process_options("spawn_helper1", exit_cb_expect_eperm); init_process_options("spawn_helper1", fail_cb);
options.flags |= UV_PROCESS_SETUID; options.flags |= UV_PROCESS_SETUID;
options.uid = 0; options.uid = 0;
r = uv_spawn(uv_default_loop(), &process, &options); r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT(r == 0); ASSERT(r == UV_EPERM);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0); ASSERT(r == 0);
ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 0);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;
@ -883,19 +862,18 @@ TEST_IMPL(spawn_setgid_fails) {
ASSERT(0 == setuid(pw->pw_uid)); ASSERT(0 == setuid(pw->pw_uid));
} }
init_process_options("spawn_helper1", exit_cb_expect_eperm); init_process_options("spawn_helper1", fail_cb);
options.flags |= UV_PROCESS_SETGID; options.flags |= UV_PROCESS_SETGID;
options.gid = 0; options.gid = 0;
r = uv_spawn(uv_default_loop(), &process, &options); r = uv_spawn(uv_default_loop(), &process, &options);
ASSERT(r == 0); ASSERT(r == UV_EPERM);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(r == 0); ASSERT(r == 0);
ASSERT(exit_cb_called == 1); ASSERT(close_cb_called == 0);
ASSERT(close_cb_called == 1);
MAKE_VALGRIND_HAPPY(); MAKE_VALGRIND_HAPPY();
return 0; return 0;

183
deps/uv/test/test-tcp-close-accept.c

@ -0,0 +1,183 @@
/* 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 <string.h>
static struct sockaddr_in addr;
static uv_tcp_t tcp_server;
static uv_tcp_t tcp_outgoing[2];
static uv_tcp_t tcp_incoming[ARRAY_SIZE(tcp_outgoing)];
static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)];
static uv_tcp_t tcp_check;
static uv_connect_t tcp_check_req;
static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)];
static unsigned int got_connections;
static unsigned int close_cb_called;
static unsigned int write_cb_called;
static unsigned int read_cb_called;
static void close_cb(uv_handle_t* handle) {
close_cb_called++;
}
static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
write_cb_called++;
}
static void connect_cb(uv_connect_t* req, int status) {
unsigned int i;
uv_buf_t buf;
uv_stream_t* outgoing;
if (req == &tcp_check_req) {
ASSERT(status != 0);
/* Close check and incoming[0], time to finish test */
uv_close((uv_handle_t*) &tcp_incoming[0], close_cb);
uv_close((uv_handle_t*) &tcp_check, close_cb);
return;
}
ASSERT(status == 0);
ASSERT(connect_reqs <= req);
ASSERT(req <= connect_reqs + ARRAY_SIZE(connect_reqs));
i = req - connect_reqs;
buf = uv_buf_init("x", 1);
outgoing = (uv_stream_t*) &tcp_outgoing[i];
ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb));
}
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
static char slab[1];
buf->base = slab;
buf->len = sizeof(slab);
}
static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
uv_loop_t* loop;
unsigned int i;
/* Only first stream should receive read events */
ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]);
ASSERT(0 == uv_read_stop(stream));
ASSERT(1 == nread);
loop = stream->loop;
read_cb_called++;
/* Close all active incomings, except current one */
for (i = 1; i < got_connections; i++)
uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
/* Create new fd that should be one of the closed incomings */
ASSERT(0 == uv_tcp_init(loop, &tcp_check));
ASSERT(0 == uv_tcp_connect(&tcp_check_req,
&tcp_check,
(const struct sockaddr*) &addr,
connect_cb));
ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb));
/* Close server, so no one will connect to it */
uv_close((uv_handle_t*) &tcp_server, close_cb);
}
static void connection_cb(uv_stream_t* server, int status) {
unsigned int i;
uv_tcp_t* incoming;
ASSERT(server == (uv_stream_t*) &tcp_server);
/* Ignore tcp_check connection */
if (got_connections == ARRAY_SIZE(tcp_incoming))
return;
/* Accept everyone */
incoming = &tcp_incoming[got_connections++];
ASSERT(0 == uv_tcp_init(server->loop, incoming));
ASSERT(0 == uv_accept(server, (uv_stream_t*) incoming));
if (got_connections != ARRAY_SIZE(tcp_incoming))
return;
/* Once all clients are accepted - start reading */
for (i = 0; i < ARRAY_SIZE(tcp_incoming); i++) {
incoming = &tcp_incoming[i];
ASSERT(0 == uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb));
}
}
TEST_IMPL(tcp_close_accept) {
unsigned int i;
uv_loop_t* loop;
uv_tcp_t* client;
/*
* A little explanation of what goes on below:
*
* We'll create server and connect to it using two clients, each writing one
* byte once connected.
*
* When all clients will be accepted by server - we'll start reading from them
* and, on first client's first byte, will close second client and server.
* After that, we'll immediately initiate new connection to server using
* tcp_check handle (thus, reusing fd from second client).
*
* In this situation uv__io_poll()'s event list should still contain read
* event for second client, and, if not cleaned up properly, `tcp_check` will
* receive stale event of second incoming and invoke `connect_cb` with zero
* status.
*/
loop = uv_default_loop();
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
ASSERT(0 == uv_tcp_init(loop, &tcp_server));
ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr));
ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server,
ARRAY_SIZE(tcp_outgoing),
connection_cb));
for (i = 0; i < ARRAY_SIZE(tcp_outgoing); i++) {
client = tcp_outgoing + i;
ASSERT(0 == uv_tcp_init(loop, client));
ASSERT(0 == uv_tcp_connect(&connect_reqs[i],
client,
(const struct sockaddr*) &addr,
connect_cb));
}
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(ARRAY_SIZE(tcp_outgoing) == got_connections);
ASSERT((ARRAY_SIZE(tcp_outgoing) + 2) == close_cb_called);
ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called);
ASSERT(1 == read_cb_called);
MAKE_VALGRIND_HAPPY();
return 0;
}

97
deps/uv/test/test-util.c

@ -1,97 +0,0 @@
/* 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 <string.h>
#define memeq(a, b, c) (memcmp((a), (b), (c)) == 0)
TEST_IMPL(strlcpy) {
size_t r;
{
char dst[2] = "A";
r = uv_strlcpy(dst, "", 0);
ASSERT(r == 0);
ASSERT(memeq(dst, "A", 1));
}
{
char dst[2] = "A";
r = uv_strlcpy(dst, "B", 1);
ASSERT(r == 0);
ASSERT(memeq(dst, "", 1));
}
{
char dst[2] = "A";
r = uv_strlcpy(dst, "B", 2);
ASSERT(r == 1);
ASSERT(memeq(dst, "B", 2));
}
{
char dst[3] = "AB";
r = uv_strlcpy(dst, "CD", 3);
ASSERT(r == 2);
ASSERT(memeq(dst, "CD", 3));
}
return 0;
}
TEST_IMPL(strlcat) {
size_t r;
{
char dst[2] = "A";
r = uv_strlcat(dst, "B", 1);
ASSERT(r == 1);
ASSERT(memeq(dst, "A", 2));
}
{
char dst[2] = "A";
r = uv_strlcat(dst, "B", 2);
ASSERT(r == 1);
ASSERT(memeq(dst, "A", 2));
}
{
char dst[3] = "A";
r = uv_strlcat(dst, "B", 3);
ASSERT(r == 2);
ASSERT(memeq(dst, "AB", 3));
}
{
char dst[5] = "AB";
r = uv_strlcat(dst, "CD", 5);
ASSERT(r == 4);
ASSERT(memeq(dst, "ABCD", 5));
}
return 0;
}

101
deps/uv/test/test-watcher-cross-stop.c

@ -0,0 +1,101 @@
/* 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 <string.h>
#include <errno.h>
/* NOTE: Number should be big enough to trigger this problem */
static uv_udp_t sockets[2500];
static uv_udp_send_t reqs[ARRAY_SIZE(sockets)];
static char slab[1];
static unsigned int recv_cb_called;
static unsigned int send_cb_called;
static unsigned int close_cb_called;
static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
buf->base = slab;
buf->len = sizeof(slab);
}
static void recv_cb(uv_udp_t* handle,
ssize_t nread,
const uv_buf_t* buf,
const struct sockaddr* addr,
unsigned flags) {
recv_cb_called++;
}
static void send_cb(uv_udp_send_t* req, int status) {
send_cb_called++;
}
static void close_cb(uv_handle_t* handle) {
close_cb_called++;
}
TEST_IMPL(watcher_cross_stop) {
uv_loop_t* loop = uv_default_loop();
unsigned int i;
struct sockaddr_in addr;
uv_buf_t buf;
char big_string[1024];
TEST_FILE_LIMIT(ARRAY_SIZE(sockets) + 32);
ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
memset(big_string, 'A', sizeof(big_string));
buf = uv_buf_init(big_string, sizeof(big_string));
for (i = 0; i < ARRAY_SIZE(sockets); i++) {
ASSERT(0 == uv_udp_init(loop, &sockets[i]));
ASSERT(0 == uv_udp_bind(&sockets[i], (const struct sockaddr*) &addr, 0));
ASSERT(0 == uv_udp_recv_start(&sockets[i], alloc_cb, recv_cb));
ASSERT(0 == uv_udp_send(&reqs[i],
&sockets[i],
&buf,
1,
(const struct sockaddr*) &addr,
send_cb));
}
while (recv_cb_called == 0)
uv_run(loop, UV_RUN_ONCE);
for (i = 0; i < ARRAY_SIZE(sockets); i++)
uv_close((uv_handle_t*) &sockets[i], close_cb);
ASSERT(0 < recv_cb_called && recv_cb_called <= ARRAY_SIZE(sockets));
ASSERT(ARRAY_SIZE(sockets) == send_cb_called);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(ARRAY_SIZE(sockets) == close_cb_called);
MAKE_VALGRIND_HAPPY();
return 0;
}

4
deps/uv/uv.gyp

@ -297,12 +297,12 @@
'test/runner.h', 'test/runner.h',
'test/test-get-loadavg.c', 'test/test-get-loadavg.c',
'test/task.h', 'test/task.h',
'test/test-util.c',
'test/test-active.c', 'test/test-active.c',
'test/test-async.c', 'test/test-async.c',
'test/test-async-null-cb.c', 'test/test-async-null-cb.c',
'test/test-callback-stack.c', 'test/test-callback-stack.c',
'test/test-callback-order.c', 'test/test-callback-order.c',
'test/test-close-fd.c',
'test/test-close-order.c', 'test/test-close-order.c',
'test/test-connection-fail.c', 'test/test-connection-fail.c',
'test/test-cwd-and-chdir.c', 'test/test-cwd-and-chdir.c',
@ -324,6 +324,7 @@
'test/test-loop-handles.c', 'test/test-loop-handles.c',
'test/test-loop-stop.c', 'test/test-loop-stop.c',
'test/test-walk-handles.c', 'test/test-walk-handles.c',
'test/test-watcher-cross-stop.c',
'test/test-multiple-listen.c', 'test/test-multiple-listen.c',
'test/test-osx-select.c', 'test/test-osx-select.c',
'test/test-pass-always.c', 'test/test-pass-always.c',
@ -348,6 +349,7 @@
'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.c', 'test/test-tcp-close.c',
'test/test-tcp-close-accept.c',
'test/test-tcp-close-while-connecting.c', 'test/test-tcp-close-while-connecting.c',
'test/test-tcp-connect-error-after-write.c', 'test/test-tcp-connect-error-after-write.c',
'test/test-tcp-shutdown-after-write.c', 'test/test-tcp-shutdown-after-write.c',

2
deps/uv/vcbuild.bat

@ -91,7 +91,7 @@ exit /b 1
:have_gyp :have_gyp
if not defined PYTHON set PYTHON="python" if not defined PYTHON set PYTHON="python"
%PYTHON% gyp_uv -Dtarget_arch=%target_arch% -Dlibrary=%library% %PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Dlibrary=%library%
if errorlevel 1 goto create-msvs-files-failed if errorlevel 1 goto create-msvs-files-failed
if not exist uv.sln goto create-msvs-files-failed if not exist uv.sln goto create-msvs-files-failed
echo Project files generated. echo Project files generated.

Loading…
Cancel
Save