foolio 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +21 -0
- data/examples/timer.rb +20 -0
- data/ext/foolio/extconf.rb +34 -0
- data/ext/foolio/foolio_ext.c +921 -0
- data/ext/foolio/gen.rb +50 -0
- data/ext/foolio/make_table.rb +12 -0
- data/ext/foolio/templ +243 -0
- data/ext/libuv/.gitignore +33 -0
- data/ext/libuv/.mailmap +13 -0
- data/ext/libuv/.travis.yml +9 -0
- data/ext/libuv/AUTHORS +61 -0
- data/ext/libuv/LICENSE +44 -0
- data/ext/libuv/Makefile +71 -0
- data/ext/libuv/README.md +90 -0
- data/ext/libuv/common.gypi +178 -0
- data/ext/libuv/gyp_uv +73 -0
- data/ext/libuv/include/uv-private/eio.h +403 -0
- data/ext/libuv/include/uv-private/ev.h +838 -0
- data/ext/libuv/include/uv-private/ngx-queue.h +108 -0
- data/ext/libuv/include/uv-private/tree.h +768 -0
- data/ext/libuv/include/uv-private/uv-unix.h +324 -0
- data/ext/libuv/include/uv-private/uv-win.h +517 -0
- data/ext/libuv/include/uv.h +1838 -0
- data/ext/libuv/src/fs-poll.c +235 -0
- data/ext/libuv/src/inet.c +293 -0
- data/ext/libuv/src/unix/async.c +148 -0
- data/ext/libuv/src/unix/core.c +696 -0
- data/ext/libuv/src/unix/cygwin.c +83 -0
- data/ext/libuv/src/unix/darwin.c +342 -0
- data/ext/libuv/src/unix/dl.c +83 -0
- data/ext/libuv/src/unix/eio/Changes +63 -0
- data/ext/libuv/src/unix/eio/LICENSE +36 -0
- data/ext/libuv/src/unix/eio/Makefile.am +15 -0
- data/ext/libuv/src/unix/eio/aclocal.m4 +8957 -0
- data/ext/libuv/src/unix/eio/autogen.sh +3 -0
- data/ext/libuv/src/unix/eio/config.h.in +86 -0
- data/ext/libuv/src/unix/eio/config_cygwin.h +80 -0
- data/ext/libuv/src/unix/eio/config_darwin.h +141 -0
- data/ext/libuv/src/unix/eio/config_freebsd.h +81 -0
- data/ext/libuv/src/unix/eio/config_linux.h +94 -0
- data/ext/libuv/src/unix/eio/config_netbsd.h +81 -0
- data/ext/libuv/src/unix/eio/config_openbsd.h +137 -0
- data/ext/libuv/src/unix/eio/config_sunos.h +84 -0
- data/ext/libuv/src/unix/eio/configure.ac +22 -0
- data/ext/libuv/src/unix/eio/demo.c +194 -0
- data/ext/libuv/src/unix/eio/ecb.h +370 -0
- data/ext/libuv/src/unix/eio/eio.3 +3428 -0
- data/ext/libuv/src/unix/eio/eio.c +2593 -0
- data/ext/libuv/src/unix/eio/eio.pod +969 -0
- data/ext/libuv/src/unix/eio/libeio.m4 +195 -0
- data/ext/libuv/src/unix/eio/xthread.h +164 -0
- data/ext/libuv/src/unix/error.c +105 -0
- data/ext/libuv/src/unix/ev/Changes +388 -0
- data/ext/libuv/src/unix/ev/LICENSE +36 -0
- data/ext/libuv/src/unix/ev/Makefile.am +18 -0
- data/ext/libuv/src/unix/ev/Makefile.in +771 -0
- data/ext/libuv/src/unix/ev/README +58 -0
- data/ext/libuv/src/unix/ev/aclocal.m4 +8957 -0
- data/ext/libuv/src/unix/ev/autogen.sh +6 -0
- data/ext/libuv/src/unix/ev/config.guess +1526 -0
- data/ext/libuv/src/unix/ev/config.h.in +125 -0
- data/ext/libuv/src/unix/ev/config.sub +1658 -0
- data/ext/libuv/src/unix/ev/config_cygwin.h +123 -0
- data/ext/libuv/src/unix/ev/config_darwin.h +122 -0
- data/ext/libuv/src/unix/ev/config_freebsd.h +120 -0
- data/ext/libuv/src/unix/ev/config_linux.h +141 -0
- data/ext/libuv/src/unix/ev/config_netbsd.h +120 -0
- data/ext/libuv/src/unix/ev/config_openbsd.h +126 -0
- data/ext/libuv/src/unix/ev/config_sunos.h +122 -0
- data/ext/libuv/src/unix/ev/configure +13037 -0
- data/ext/libuv/src/unix/ev/configure.ac +18 -0
- data/ext/libuv/src/unix/ev/depcomp +630 -0
- data/ext/libuv/src/unix/ev/ev++.h +816 -0
- data/ext/libuv/src/unix/ev/ev.3 +5311 -0
- data/ext/libuv/src/unix/ev/ev.c +3925 -0
- data/ext/libuv/src/unix/ev/ev.pod +5243 -0
- data/ext/libuv/src/unix/ev/ev_epoll.c +266 -0
- data/ext/libuv/src/unix/ev/ev_kqueue.c +235 -0
- data/ext/libuv/src/unix/ev/ev_poll.c +148 -0
- data/ext/libuv/src/unix/ev/ev_port.c +179 -0
- data/ext/libuv/src/unix/ev/ev_select.c +310 -0
- data/ext/libuv/src/unix/ev/ev_vars.h +203 -0
- data/ext/libuv/src/unix/ev/ev_win32.c +153 -0
- data/ext/libuv/src/unix/ev/ev_wrap.h +196 -0
- data/ext/libuv/src/unix/ev/event.c +402 -0
- data/ext/libuv/src/unix/ev/event.h +170 -0
- data/ext/libuv/src/unix/ev/install-sh +294 -0
- data/ext/libuv/src/unix/ev/libev.m4 +39 -0
- data/ext/libuv/src/unix/ev/ltmain.sh +8413 -0
- data/ext/libuv/src/unix/ev/missing +336 -0
- data/ext/libuv/src/unix/ev/mkinstalldirs +111 -0
- data/ext/libuv/src/unix/freebsd.c +326 -0
- data/ext/libuv/src/unix/fs.c +739 -0
- data/ext/libuv/src/unix/internal.h +188 -0
- data/ext/libuv/src/unix/kqueue.c +120 -0
- data/ext/libuv/src/unix/linux/inotify.c +239 -0
- data/ext/libuv/src/unix/linux/linux-core.c +557 -0
- data/ext/libuv/src/unix/linux/syscalls.c +388 -0
- data/ext/libuv/src/unix/linux/syscalls.h +124 -0
- data/ext/libuv/src/unix/loop-watcher.c +62 -0
- data/ext/libuv/src/unix/loop.c +94 -0
- data/ext/libuv/src/unix/netbsd.c +108 -0
- data/ext/libuv/src/unix/openbsd.c +295 -0
- data/ext/libuv/src/unix/pipe.c +259 -0
- data/ext/libuv/src/unix/poll.c +114 -0
- data/ext/libuv/src/unix/process.c +495 -0
- data/ext/libuv/src/unix/signal.c +269 -0
- data/ext/libuv/src/unix/stream.c +990 -0
- data/ext/libuv/src/unix/sunos.c +481 -0
- data/ext/libuv/src/unix/tcp.c +393 -0
- data/ext/libuv/src/unix/thread.c +251 -0
- data/ext/libuv/src/unix/timer.c +136 -0
- data/ext/libuv/src/unix/tty.c +145 -0
- data/ext/libuv/src/unix/udp.c +659 -0
- data/ext/libuv/src/unix/uv-eio.c +107 -0
- data/ext/libuv/src/unix/uv-eio.h +13 -0
- data/ext/libuv/src/uv-common.c +380 -0
- data/ext/libuv/src/uv-common.h +170 -0
- data/ext/libuv/src/win/async.c +100 -0
- data/ext/libuv/src/win/atomicops-inl.h +56 -0
- data/ext/libuv/src/win/core.c +278 -0
- data/ext/libuv/src/win/dl.c +86 -0
- data/ext/libuv/src/win/error.c +155 -0
- data/ext/libuv/src/win/fs-event.c +510 -0
- data/ext/libuv/src/win/fs.c +1948 -0
- data/ext/libuv/src/win/getaddrinfo.c +365 -0
- data/ext/libuv/src/win/handle-inl.h +149 -0
- data/ext/libuv/src/win/handle.c +154 -0
- data/ext/libuv/src/win/internal.h +343 -0
- data/ext/libuv/src/win/loop-watcher.c +122 -0
- data/ext/libuv/src/win/pipe.c +1672 -0
- data/ext/libuv/src/win/poll.c +616 -0
- data/ext/libuv/src/win/process-stdio.c +500 -0
- data/ext/libuv/src/win/process.c +1013 -0
- data/ext/libuv/src/win/req-inl.h +220 -0
- data/ext/libuv/src/win/req.c +25 -0
- data/ext/libuv/src/win/signal.c +57 -0
- data/ext/libuv/src/win/stream-inl.h +67 -0
- data/ext/libuv/src/win/stream.c +167 -0
- data/ext/libuv/src/win/tcp.c +1394 -0
- data/ext/libuv/src/win/thread.c +372 -0
- data/ext/libuv/src/win/threadpool.c +74 -0
- data/ext/libuv/src/win/timer.c +224 -0
- data/ext/libuv/src/win/tty.c +1799 -0
- data/ext/libuv/src/win/udp.c +716 -0
- data/ext/libuv/src/win/util.c +864 -0
- data/ext/libuv/src/win/winapi.c +132 -0
- data/ext/libuv/src/win/winapi.h +4452 -0
- data/ext/libuv/src/win/winsock.c +557 -0
- data/ext/libuv/src/win/winsock.h +171 -0
- data/ext/libuv/test/benchmark-async-pummel.c +97 -0
- data/ext/libuv/test/benchmark-async.c +137 -0
- data/ext/libuv/test/benchmark-fs-stat.c +135 -0
- data/ext/libuv/test/benchmark-getaddrinfo.c +94 -0
- data/ext/libuv/test/benchmark-list.h +127 -0
- data/ext/libuv/test/benchmark-loop-count.c +88 -0
- data/ext/libuv/test/benchmark-million-timers.c +65 -0
- data/ext/libuv/test/benchmark-ping-pongs.c +213 -0
- data/ext/libuv/test/benchmark-pound.c +324 -0
- data/ext/libuv/test/benchmark-pump.c +462 -0
- data/ext/libuv/test/benchmark-sizes.c +44 -0
- data/ext/libuv/test/benchmark-spawn.c +162 -0
- data/ext/libuv/test/benchmark-tcp-write-batch.c +140 -0
- data/ext/libuv/test/benchmark-thread.c +64 -0
- data/ext/libuv/test/benchmark-udp-packet-storm.c +247 -0
- data/ext/libuv/test/blackhole-server.c +118 -0
- data/ext/libuv/test/dns-server.c +321 -0
- data/ext/libuv/test/echo-server.c +378 -0
- data/ext/libuv/test/fixtures/empty_file +0 -0
- data/ext/libuv/test/fixtures/load_error.node +1 -0
- data/ext/libuv/test/run-benchmarks.c +64 -0
- data/ext/libuv/test/run-tests.c +138 -0
- data/ext/libuv/test/runner-unix.c +295 -0
- data/ext/libuv/test/runner-unix.h +36 -0
- data/ext/libuv/test/runner-win.c +285 -0
- data/ext/libuv/test/runner-win.h +42 -0
- data/ext/libuv/test/runner.c +355 -0
- data/ext/libuv/test/runner.h +159 -0
- data/ext/libuv/test/task.h +112 -0
- data/ext/libuv/test/test-async.c +118 -0
- data/ext/libuv/test/test-callback-order.c +76 -0
- data/ext/libuv/test/test-callback-stack.c +203 -0
- data/ext/libuv/test/test-connection-fail.c +148 -0
- data/ext/libuv/test/test-cwd-and-chdir.c +64 -0
- data/ext/libuv/test/test-delayed-accept.c +188 -0
- data/ext/libuv/test/test-dlerror.c +58 -0
- data/ext/libuv/test/test-error.c +59 -0
- data/ext/libuv/test/test-fail-always.c +29 -0
- data/ext/libuv/test/test-fs-event.c +474 -0
- data/ext/libuv/test/test-fs-poll.c +146 -0
- data/ext/libuv/test/test-fs.c +1843 -0
- data/ext/libuv/test/test-get-currentexe.c +63 -0
- data/ext/libuv/test/test-get-loadavg.c +36 -0
- data/ext/libuv/test/test-get-memory.c +38 -0
- data/ext/libuv/test/test-getaddrinfo.c +122 -0
- data/ext/libuv/test/test-getsockname.c +342 -0
- data/ext/libuv/test/test-hrtime.c +54 -0
- data/ext/libuv/test/test-idle.c +81 -0
- data/ext/libuv/test/test-ipc-send-recv.c +209 -0
- data/ext/libuv/test/test-ipc.c +620 -0
- data/ext/libuv/test/test-list.h +427 -0
- data/ext/libuv/test/test-loop-handles.c +336 -0
- data/ext/libuv/test/test-multiple-listen.c +102 -0
- data/ext/libuv/test/test-mutexes.c +63 -0
- data/ext/libuv/test/test-pass-always.c +28 -0
- data/ext/libuv/test/test-ping-pong.c +253 -0
- data/ext/libuv/test/test-pipe-bind-error.c +140 -0
- data/ext/libuv/test/test-pipe-connect-error.c +96 -0
- data/ext/libuv/test/test-platform-output.c +87 -0
- data/ext/libuv/test/test-poll-close.c +72 -0
- data/ext/libuv/test/test-poll.c +573 -0
- data/ext/libuv/test/test-process-title.c +49 -0
- data/ext/libuv/test/test-ref.c +338 -0
- data/ext/libuv/test/test-run-once.c +48 -0
- data/ext/libuv/test/test-semaphore.c +111 -0
- data/ext/libuv/test/test-shutdown-close.c +103 -0
- data/ext/libuv/test/test-shutdown-eof.c +183 -0
- data/ext/libuv/test/test-signal.c +162 -0
- data/ext/libuv/test/test-spawn.c +863 -0
- data/ext/libuv/test/test-stdio-over-pipes.c +246 -0
- data/ext/libuv/test/test-tcp-bind-error.c +191 -0
- data/ext/libuv/test/test-tcp-bind6-error.c +154 -0
- data/ext/libuv/test/test-tcp-close-while-connecting.c +80 -0
- data/ext/libuv/test/test-tcp-close.c +129 -0
- data/ext/libuv/test/test-tcp-connect-error-after-write.c +95 -0
- data/ext/libuv/test/test-tcp-connect-error.c +70 -0
- data/ext/libuv/test/test-tcp-connect-timeout.c +85 -0
- data/ext/libuv/test/test-tcp-connect6-error.c +68 -0
- data/ext/libuv/test/test-tcp-flags.c +51 -0
- data/ext/libuv/test/test-tcp-shutdown-after-write.c +131 -0
- data/ext/libuv/test/test-tcp-unexpected-read.c +113 -0
- data/ext/libuv/test/test-tcp-write-error.c +168 -0
- data/ext/libuv/test/test-tcp-write-to-half-open-connection.c +135 -0
- data/ext/libuv/test/test-tcp-writealot.c +170 -0
- data/ext/libuv/test/test-thread.c +183 -0
- data/ext/libuv/test/test-threadpool.c +57 -0
- data/ext/libuv/test/test-timer-again.c +141 -0
- data/ext/libuv/test/test-timer.c +152 -0
- data/ext/libuv/test/test-tty.c +110 -0
- data/ext/libuv/test/test-udp-dgram-too-big.c +86 -0
- data/ext/libuv/test/test-udp-ipv6.c +156 -0
- data/ext/libuv/test/test-udp-multicast-join.c +139 -0
- data/ext/libuv/test/test-udp-multicast-ttl.c +86 -0
- data/ext/libuv/test/test-udp-options.c +86 -0
- data/ext/libuv/test/test-udp-send-and-recv.c +208 -0
- data/ext/libuv/test/test-util.c +97 -0
- data/ext/libuv/test/test-walk-handles.c +77 -0
- data/ext/libuv/uv.gyp +375 -0
- data/ext/libuv/vcbuild.bat +105 -0
- data/foolio.gemspec +18 -0
- data/lib/foolio.rb +9 -0
- data/lib/foolio/handle.rb +27 -0
- data/lib/foolio/listener.rb +26 -0
- data/lib/foolio/loop.rb +79 -0
- data/lib/foolio/stream.rb +109 -0
- data/lib/foolio/version.rb +3 -0
- metadata +309 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
2
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3
|
+
* of this software and associated documentation files (the "Software"), to
|
|
4
|
+
* deal in the Software without restriction, including without limitation the
|
|
5
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
6
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
|
7
|
+
* furnished to do so, subject to the following conditions:
|
|
8
|
+
*
|
|
9
|
+
* The above copyright notice and this permission notice shall be included in
|
|
10
|
+
* all copies or substantial portions of the Software.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
13
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
14
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
15
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
16
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
17
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
18
|
+
* IN THE SOFTWARE.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
#include "uv.h"
|
|
22
|
+
#include "internal.h"
|
|
23
|
+
#include <assert.h>
|
|
24
|
+
|
|
25
|
+
static int uv__timer_cmp(const uv_timer_t* a, const uv_timer_t* b) {
|
|
26
|
+
if (a->timeout < b->timeout)
|
|
27
|
+
return -1;
|
|
28
|
+
if (a->timeout > b->timeout)
|
|
29
|
+
return 1;
|
|
30
|
+
if (a < b)
|
|
31
|
+
return -1;
|
|
32
|
+
if (a > b)
|
|
33
|
+
return 1;
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
|
|
42
|
+
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
|
|
43
|
+
handle->timer_cb = NULL;
|
|
44
|
+
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
int uv_timer_start(uv_timer_t* handle,
|
|
50
|
+
uv_timer_cb cb,
|
|
51
|
+
int64_t timeout,
|
|
52
|
+
int64_t repeat) {
|
|
53
|
+
assert(timeout >= 0);
|
|
54
|
+
assert(repeat >= 0);
|
|
55
|
+
|
|
56
|
+
if (uv__is_active(handle))
|
|
57
|
+
uv_timer_stop(handle);
|
|
58
|
+
|
|
59
|
+
handle->timer_cb = cb;
|
|
60
|
+
handle->timeout = handle->loop->time + timeout;
|
|
61
|
+
handle->repeat = repeat;
|
|
62
|
+
|
|
63
|
+
RB_INSERT(uv__timers, &handle->loop->timer_handles, handle);
|
|
64
|
+
uv__handle_start(handle);
|
|
65
|
+
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
int uv_timer_stop(uv_timer_t* handle) {
|
|
71
|
+
if (!uv__is_active(handle))
|
|
72
|
+
return 0;
|
|
73
|
+
|
|
74
|
+
RB_REMOVE(uv__timers, &handle->loop->timer_handles, handle);
|
|
75
|
+
uv__handle_stop(handle);
|
|
76
|
+
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
int uv_timer_again(uv_timer_t* handle) {
|
|
82
|
+
if (handle->timer_cb == NULL)
|
|
83
|
+
return uv__set_artificial_error(handle->loop, UV_EINVAL);
|
|
84
|
+
|
|
85
|
+
if (handle->repeat) {
|
|
86
|
+
uv_timer_stop(handle);
|
|
87
|
+
uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
void uv_timer_set_repeat(uv_timer_t* handle, int64_t repeat) {
|
|
95
|
+
assert(repeat >= 0);
|
|
96
|
+
handle->repeat = repeat;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
int64_t uv_timer_get_repeat(uv_timer_t* handle) {
|
|
101
|
+
return handle->repeat;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
unsigned int uv__next_timeout(uv_loop_t* loop) {
|
|
106
|
+
uv_timer_t* handle;
|
|
107
|
+
|
|
108
|
+
handle = RB_MIN(uv__timers, &loop->timer_handles);
|
|
109
|
+
|
|
110
|
+
if (handle == NULL)
|
|
111
|
+
return (unsigned int) -1; /* block indefinitely */
|
|
112
|
+
|
|
113
|
+
if (handle->timeout <= loop->time)
|
|
114
|
+
return 0;
|
|
115
|
+
|
|
116
|
+
return handle->timeout - loop->time;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
void uv__run_timers(uv_loop_t* loop) {
|
|
121
|
+
uv_timer_t* handle;
|
|
122
|
+
|
|
123
|
+
while ((handle = RB_MIN(uv__timers, &loop->timer_handles))) {
|
|
124
|
+
if (handle->timeout > loop->time)
|
|
125
|
+
break;
|
|
126
|
+
|
|
127
|
+
uv_timer_stop(handle);
|
|
128
|
+
uv_timer_again(handle);
|
|
129
|
+
handle->timer_cb(handle, 0);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
void uv__timer_close(uv_timer_t* handle) {
|
|
135
|
+
uv_timer_stop(handle);
|
|
136
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
* of this software and associated documentation files (the "Software"), to
|
|
5
|
+
* deal in the Software without restriction, including without limitation the
|
|
6
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
7
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
* furnished to do so, subject to the following conditions:
|
|
9
|
+
*
|
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
|
11
|
+
* all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
19
|
+
* IN THE SOFTWARE.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#include "uv.h"
|
|
23
|
+
#include "internal.h"
|
|
24
|
+
|
|
25
|
+
#include <assert.h>
|
|
26
|
+
#include <unistd.h>
|
|
27
|
+
#include <termios.h>
|
|
28
|
+
#include <errno.h>
|
|
29
|
+
#include <sys/ioctl.h>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
static int orig_termios_fd = -1;
|
|
33
|
+
static struct termios orig_termios;
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
|
37
|
+
uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY);
|
|
38
|
+
|
|
39
|
+
if (readable) {
|
|
40
|
+
uv__nonblock(fd, 1);
|
|
41
|
+
uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE);
|
|
42
|
+
} else {
|
|
43
|
+
/* Note: writable tty we set to blocking mode. */
|
|
44
|
+
uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE);
|
|
45
|
+
tty->flags |= UV_STREAM_BLOCKING;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
tty->mode = 0;
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
int uv_tty_set_mode(uv_tty_t* tty, int mode) {
|
|
54
|
+
int fd = tty->fd;
|
|
55
|
+
struct termios raw;
|
|
56
|
+
|
|
57
|
+
if (mode && tty->mode == 0) {
|
|
58
|
+
/* on */
|
|
59
|
+
|
|
60
|
+
if (tcgetattr(fd, &tty->orig_termios)) {
|
|
61
|
+
goto fatal;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* This is used for uv_tty_reset_mode() */
|
|
65
|
+
if (orig_termios_fd == -1) {
|
|
66
|
+
orig_termios = tty->orig_termios;
|
|
67
|
+
orig_termios_fd = fd;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
raw = tty->orig_termios;
|
|
71
|
+
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
|
72
|
+
raw.c_oflag |= (ONLCR);
|
|
73
|
+
raw.c_cflag |= (CS8);
|
|
74
|
+
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
|
|
75
|
+
raw.c_cc[VMIN] = 1;
|
|
76
|
+
raw.c_cc[VTIME] = 0;
|
|
77
|
+
|
|
78
|
+
/* Put terminal in raw mode after draining */
|
|
79
|
+
if (tcsetattr(fd, TCSADRAIN, &raw)) {
|
|
80
|
+
goto fatal;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
tty->mode = 1;
|
|
84
|
+
return 0;
|
|
85
|
+
} else if (mode == 0 && tty->mode) {
|
|
86
|
+
/* off */
|
|
87
|
+
|
|
88
|
+
/* Put terminal in original mode after flushing */
|
|
89
|
+
if (tcsetattr(fd, TCSAFLUSH, &tty->orig_termios)) {
|
|
90
|
+
goto fatal;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
tty->mode = 0;
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fatal:
|
|
98
|
+
uv__set_sys_error(tty->loop, errno);
|
|
99
|
+
return -1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
|
104
|
+
struct winsize ws;
|
|
105
|
+
|
|
106
|
+
if (ioctl(tty->fd, TIOCGWINSZ, &ws) < 0) {
|
|
107
|
+
uv__set_sys_error(tty->loop, errno);
|
|
108
|
+
return -1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
*width = ws.ws_col;
|
|
112
|
+
*height = ws.ws_row;
|
|
113
|
+
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
uv_handle_type uv_guess_handle(uv_file file) {
|
|
119
|
+
struct stat s;
|
|
120
|
+
|
|
121
|
+
if (file < 0) {
|
|
122
|
+
return UV_UNKNOWN_HANDLE;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (isatty(file)) {
|
|
126
|
+
return UV_TTY;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (fstat(file, &s)) {
|
|
130
|
+
return UV_UNKNOWN_HANDLE;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!S_ISSOCK(s.st_mode) && !S_ISFIFO(s.st_mode)) {
|
|
134
|
+
return UV_FILE;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return UV_NAMED_PIPE;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
void uv_tty_reset_mode() {
|
|
142
|
+
if (orig_termios_fd >= 0) {
|
|
143
|
+
tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
* of this software and associated documentation files (the "Software"), to
|
|
5
|
+
* deal in the Software without restriction, including without limitation the
|
|
6
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
7
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
* furnished to do so, subject to the following conditions:
|
|
9
|
+
*
|
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
|
11
|
+
* all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
19
|
+
* IN THE SOFTWARE.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#include "uv.h"
|
|
23
|
+
#include "internal.h"
|
|
24
|
+
|
|
25
|
+
#include <assert.h>
|
|
26
|
+
#include <string.h>
|
|
27
|
+
#include <errno.h>
|
|
28
|
+
#include <stdlib.h>
|
|
29
|
+
#include <unistd.h>
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
static void uv__udp_run_completed(uv_udp_t* handle);
|
|
33
|
+
static void uv__udp_run_pending(uv_udp_t* handle);
|
|
34
|
+
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents);
|
|
35
|
+
static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, int revents);
|
|
36
|
+
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain);
|
|
37
|
+
static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
|
|
38
|
+
int bufcnt, struct sockaddr* addr, socklen_t addrlen, uv_udp_send_cb send_cb);
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
static void uv__udp_start_watcher(uv_udp_t* handle,
|
|
42
|
+
uv__io_t* w,
|
|
43
|
+
uv__io_cb cb,
|
|
44
|
+
int events) {
|
|
45
|
+
if (uv__io_active(w)) return;
|
|
46
|
+
uv__io_init(w, cb, handle->fd, events);
|
|
47
|
+
uv__io_start(handle->loop, w);
|
|
48
|
+
uv__handle_start(handle);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
static void uv__udp_stop_watcher(uv_udp_t* handle, uv__io_t* w) {
|
|
53
|
+
if (!uv__io_active(w)) return;
|
|
54
|
+
uv__io_stop(handle->loop, w);
|
|
55
|
+
|
|
56
|
+
if (!uv__io_active(&handle->read_watcher) &&
|
|
57
|
+
!uv__io_active(&handle->write_watcher))
|
|
58
|
+
{
|
|
59
|
+
uv__handle_stop(handle);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
void uv__udp_close(uv_udp_t* handle) {
|
|
65
|
+
uv__udp_stop_watcher(handle, &handle->write_watcher);
|
|
66
|
+
uv__udp_stop_watcher(handle, &handle->read_watcher);
|
|
67
|
+
close(handle->fd);
|
|
68
|
+
handle->fd = -1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
void uv__udp_finish_close(uv_udp_t* handle) {
|
|
73
|
+
uv_udp_send_t* req;
|
|
74
|
+
ngx_queue_t* q;
|
|
75
|
+
|
|
76
|
+
assert(!uv__io_active(&handle->write_watcher));
|
|
77
|
+
assert(!uv__io_active(&handle->read_watcher));
|
|
78
|
+
assert(handle->fd == -1);
|
|
79
|
+
|
|
80
|
+
uv__udp_run_completed(handle);
|
|
81
|
+
|
|
82
|
+
while (!ngx_queue_empty(&handle->write_queue)) {
|
|
83
|
+
q = ngx_queue_head(&handle->write_queue);
|
|
84
|
+
ngx_queue_remove(q);
|
|
85
|
+
|
|
86
|
+
req = ngx_queue_data(q, uv_udp_send_t, queue);
|
|
87
|
+
uv__req_unregister(handle->loop, req);
|
|
88
|
+
|
|
89
|
+
if (req->send_cb) {
|
|
90
|
+
/* FIXME proper error code like UV_EABORTED */
|
|
91
|
+
uv__set_artificial_error(handle->loop, UV_EINTR);
|
|
92
|
+
req->send_cb(req, -1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Now tear down the handle. */
|
|
97
|
+
handle->flags = 0;
|
|
98
|
+
handle->recv_cb = NULL;
|
|
99
|
+
handle->alloc_cb = NULL;
|
|
100
|
+
/* but _do not_ touch close_cb */
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
static void uv__udp_run_pending(uv_udp_t* handle) {
|
|
105
|
+
uv_udp_send_t* req;
|
|
106
|
+
ngx_queue_t* q;
|
|
107
|
+
struct msghdr h;
|
|
108
|
+
ssize_t size;
|
|
109
|
+
|
|
110
|
+
while (!ngx_queue_empty(&handle->write_queue)) {
|
|
111
|
+
q = ngx_queue_head(&handle->write_queue);
|
|
112
|
+
assert(q != NULL);
|
|
113
|
+
|
|
114
|
+
req = ngx_queue_data(q, uv_udp_send_t, queue);
|
|
115
|
+
assert(req != NULL);
|
|
116
|
+
|
|
117
|
+
memset(&h, 0, sizeof h);
|
|
118
|
+
h.msg_name = &req->addr;
|
|
119
|
+
h.msg_namelen = (req->addr.sin6_family == AF_INET6 ?
|
|
120
|
+
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
|
|
121
|
+
h.msg_iov = (struct iovec*)req->bufs;
|
|
122
|
+
h.msg_iovlen = req->bufcnt;
|
|
123
|
+
|
|
124
|
+
do {
|
|
125
|
+
size = sendmsg(handle->fd, &h, 0);
|
|
126
|
+
}
|
|
127
|
+
while (size == -1 && errno == EINTR);
|
|
128
|
+
|
|
129
|
+
/* TODO try to write once or twice more in the
|
|
130
|
+
* hope that the socket becomes readable again?
|
|
131
|
+
*/
|
|
132
|
+
if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
|
|
133
|
+
break;
|
|
134
|
+
|
|
135
|
+
req->status = (size == -1 ? -errno : size);
|
|
136
|
+
|
|
137
|
+
#ifndef NDEBUG
|
|
138
|
+
/* Sanity check. */
|
|
139
|
+
if (size != -1) {
|
|
140
|
+
ssize_t nbytes;
|
|
141
|
+
int i;
|
|
142
|
+
|
|
143
|
+
for (nbytes = i = 0; i < req->bufcnt; i++)
|
|
144
|
+
nbytes += req->bufs[i].len;
|
|
145
|
+
|
|
146
|
+
assert(size == nbytes);
|
|
147
|
+
}
|
|
148
|
+
#endif
|
|
149
|
+
|
|
150
|
+
/* Sending a datagram is an atomic operation: either all data
|
|
151
|
+
* is written or nothing is (and EMSGSIZE is raised). That is
|
|
152
|
+
* why we don't handle partial writes. Just pop the request
|
|
153
|
+
* off the write queue and onto the completed queue, done.
|
|
154
|
+
*/
|
|
155
|
+
ngx_queue_remove(&req->queue);
|
|
156
|
+
ngx_queue_insert_tail(&handle->write_completed_queue, &req->queue);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
static void uv__udp_run_completed(uv_udp_t* handle) {
|
|
162
|
+
uv_udp_send_t* req;
|
|
163
|
+
ngx_queue_t* q;
|
|
164
|
+
|
|
165
|
+
while (!ngx_queue_empty(&handle->write_completed_queue)) {
|
|
166
|
+
q = ngx_queue_head(&handle->write_completed_queue);
|
|
167
|
+
ngx_queue_remove(q);
|
|
168
|
+
|
|
169
|
+
req = ngx_queue_data(q, uv_udp_send_t, queue);
|
|
170
|
+
uv__req_unregister(handle->loop, req);
|
|
171
|
+
|
|
172
|
+
if (req->bufs != req->bufsml)
|
|
173
|
+
free(req->bufs);
|
|
174
|
+
|
|
175
|
+
if (req->send_cb == NULL)
|
|
176
|
+
continue;
|
|
177
|
+
|
|
178
|
+
/* req->status >= 0 == bytes written
|
|
179
|
+
* req->status < 0 == errno
|
|
180
|
+
*/
|
|
181
|
+
if (req->status >= 0) {
|
|
182
|
+
req->send_cb(req, 0);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
uv__set_sys_error(handle->loop, -req->status);
|
|
186
|
+
req->send_cb(req, -1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) {
|
|
193
|
+
struct sockaddr_storage peer;
|
|
194
|
+
struct msghdr h;
|
|
195
|
+
uv_udp_t* handle;
|
|
196
|
+
ssize_t nread;
|
|
197
|
+
uv_buf_t buf;
|
|
198
|
+
int flags;
|
|
199
|
+
int count;
|
|
200
|
+
|
|
201
|
+
handle = container_of(w, uv_udp_t, read_watcher);
|
|
202
|
+
assert(handle->type == UV_UDP);
|
|
203
|
+
assert(revents & UV__IO_READ);
|
|
204
|
+
|
|
205
|
+
assert(handle->recv_cb != NULL);
|
|
206
|
+
assert(handle->alloc_cb != NULL);
|
|
207
|
+
|
|
208
|
+
/* Prevent loop starvation when the data comes in as fast as (or faster than)
|
|
209
|
+
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
|
|
210
|
+
*/
|
|
211
|
+
count = 32;
|
|
212
|
+
|
|
213
|
+
memset(&h, 0, sizeof(h));
|
|
214
|
+
h.msg_name = &peer;
|
|
215
|
+
|
|
216
|
+
do {
|
|
217
|
+
buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024);
|
|
218
|
+
assert(buf.len > 0);
|
|
219
|
+
assert(buf.base != NULL);
|
|
220
|
+
|
|
221
|
+
h.msg_namelen = sizeof(peer);
|
|
222
|
+
h.msg_iov = (struct iovec*)&buf;
|
|
223
|
+
h.msg_iovlen = 1;
|
|
224
|
+
|
|
225
|
+
do {
|
|
226
|
+
nread = recvmsg(handle->fd, &h, 0);
|
|
227
|
+
}
|
|
228
|
+
while (nread == -1 && errno == EINTR);
|
|
229
|
+
|
|
230
|
+
if (nread == -1) {
|
|
231
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
232
|
+
uv__set_sys_error(handle->loop, EAGAIN);
|
|
233
|
+
handle->recv_cb(handle, 0, buf, NULL, 0);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
uv__set_sys_error(handle->loop, errno);
|
|
237
|
+
handle->recv_cb(handle, -1, buf, NULL, 0);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
flags = 0;
|
|
242
|
+
|
|
243
|
+
if (h.msg_flags & MSG_TRUNC)
|
|
244
|
+
flags |= UV_UDP_PARTIAL;
|
|
245
|
+
|
|
246
|
+
handle->recv_cb(handle,
|
|
247
|
+
nread,
|
|
248
|
+
buf,
|
|
249
|
+
(struct sockaddr*)&peer,
|
|
250
|
+
flags);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/* recv_cb callback may decide to pause or close the handle */
|
|
254
|
+
while (nread != -1
|
|
255
|
+
&& count-- > 0
|
|
256
|
+
&& handle->fd != -1
|
|
257
|
+
&& handle->recv_cb != NULL);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
static void uv__udp_sendmsg(uv_loop_t* loop, uv__io_t* w, int revents) {
|
|
262
|
+
uv_udp_t* handle;
|
|
263
|
+
|
|
264
|
+
handle = container_of(w, uv_udp_t, write_watcher);
|
|
265
|
+
assert(handle->type == UV_UDP);
|
|
266
|
+
assert(revents & UV__IO_WRITE);
|
|
267
|
+
|
|
268
|
+
assert(!ngx_queue_empty(&handle->write_queue)
|
|
269
|
+
|| !ngx_queue_empty(&handle->write_completed_queue));
|
|
270
|
+
|
|
271
|
+
/* Write out pending data first. */
|
|
272
|
+
uv__udp_run_pending(handle);
|
|
273
|
+
|
|
274
|
+
/* Drain 'request completed' queue. */
|
|
275
|
+
uv__udp_run_completed(handle);
|
|
276
|
+
|
|
277
|
+
if (!ngx_queue_empty(&handle->write_completed_queue)) {
|
|
278
|
+
/* Schedule completion callbacks. */
|
|
279
|
+
uv__io_feed(handle->loop, &handle->write_watcher, UV__IO_WRITE);
|
|
280
|
+
}
|
|
281
|
+
else if (ngx_queue_empty(&handle->write_queue)) {
|
|
282
|
+
/* Pending queue and completion queue empty, stop watcher. */
|
|
283
|
+
uv__udp_stop_watcher(handle, &handle->write_watcher);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
static int uv__bind(uv_udp_t* handle,
|
|
289
|
+
int domain,
|
|
290
|
+
struct sockaddr* addr,
|
|
291
|
+
socklen_t len,
|
|
292
|
+
unsigned flags) {
|
|
293
|
+
int saved_errno;
|
|
294
|
+
int status;
|
|
295
|
+
int yes;
|
|
296
|
+
int fd;
|
|
297
|
+
|
|
298
|
+
saved_errno = errno;
|
|
299
|
+
status = -1;
|
|
300
|
+
fd = -1;
|
|
301
|
+
|
|
302
|
+
/* Check for bad flags. */
|
|
303
|
+
if (flags & ~UV_UDP_IPV6ONLY) {
|
|
304
|
+
uv__set_sys_error(handle->loop, EINVAL);
|
|
305
|
+
goto out;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* Cannot set IPv6-only mode on non-IPv6 socket. */
|
|
309
|
+
if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) {
|
|
310
|
+
uv__set_sys_error(handle->loop, EINVAL);
|
|
311
|
+
goto out;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* Check for already active socket. */
|
|
315
|
+
if (handle->fd != -1) {
|
|
316
|
+
uv__set_artificial_error(handle->loop, UV_EALREADY);
|
|
317
|
+
goto out;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if ((fd = uv__socket(domain, SOCK_DGRAM, 0)) == -1) {
|
|
321
|
+
uv__set_sys_error(handle->loop, errno);
|
|
322
|
+
goto out;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
yes = 1;
|
|
326
|
+
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) {
|
|
327
|
+
uv__set_sys_error(handle->loop, errno);
|
|
328
|
+
goto out;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* On the BSDs, SO_REUSEADDR lets you reuse an address that's in the TIME_WAIT
|
|
332
|
+
* state (i.e. was until recently tied to a socket) while SO_REUSEPORT lets
|
|
333
|
+
* multiple processes bind to the same address. Yes, it's something of a
|
|
334
|
+
* misnomer but then again, SO_REUSEADDR was already taken.
|
|
335
|
+
*
|
|
336
|
+
* None of the above applies to Linux: SO_REUSEADDR implies SO_REUSEPORT on
|
|
337
|
+
* Linux and hence it does not have SO_REUSEPORT at all.
|
|
338
|
+
*/
|
|
339
|
+
#ifdef SO_REUSEPORT
|
|
340
|
+
yes = 1;
|
|
341
|
+
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) {
|
|
342
|
+
uv__set_sys_error(handle->loop, errno);
|
|
343
|
+
goto out;
|
|
344
|
+
}
|
|
345
|
+
#endif
|
|
346
|
+
|
|
347
|
+
if (flags & UV_UDP_IPV6ONLY) {
|
|
348
|
+
#ifdef IPV6_V6ONLY
|
|
349
|
+
yes = 1;
|
|
350
|
+
if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
|
|
351
|
+
uv__set_sys_error(handle->loop, errno);
|
|
352
|
+
goto out;
|
|
353
|
+
}
|
|
354
|
+
#else
|
|
355
|
+
uv__set_sys_error(handle->loop, ENOTSUP);
|
|
356
|
+
goto out;
|
|
357
|
+
#endif
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (bind(fd, addr, len) == -1) {
|
|
361
|
+
uv__set_sys_error(handle->loop, errno);
|
|
362
|
+
goto out;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
handle->fd = fd;
|
|
366
|
+
status = 0;
|
|
367
|
+
|
|
368
|
+
out:
|
|
369
|
+
if (status)
|
|
370
|
+
close(fd);
|
|
371
|
+
|
|
372
|
+
errno = saved_errno;
|
|
373
|
+
return status;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, int domain) {
|
|
378
|
+
struct sockaddr_storage taddr;
|
|
379
|
+
socklen_t addrlen;
|
|
380
|
+
|
|
381
|
+
assert(domain == AF_INET || domain == AF_INET6);
|
|
382
|
+
|
|
383
|
+
if (handle->fd != -1)
|
|
384
|
+
return 0;
|
|
385
|
+
|
|
386
|
+
switch (domain) {
|
|
387
|
+
case AF_INET:
|
|
388
|
+
{
|
|
389
|
+
struct sockaddr_in* addr = (void*)&taddr;
|
|
390
|
+
memset(addr, 0, sizeof *addr);
|
|
391
|
+
addr->sin_family = AF_INET;
|
|
392
|
+
addr->sin_addr.s_addr = INADDR_ANY;
|
|
393
|
+
addrlen = sizeof *addr;
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
case AF_INET6:
|
|
397
|
+
{
|
|
398
|
+
struct sockaddr_in6* addr = (void*)&taddr;
|
|
399
|
+
memset(addr, 0, sizeof *addr);
|
|
400
|
+
addr->sin6_family = AF_INET6;
|
|
401
|
+
addr->sin6_addr = in6addr_any;
|
|
402
|
+
addrlen = sizeof *addr;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
default:
|
|
406
|
+
assert(0 && "unsupported address family");
|
|
407
|
+
abort();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return uv__bind(handle, domain, (struct sockaddr*)&taddr, addrlen, 0);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
static int uv__udp_send(uv_udp_send_t* req,
|
|
415
|
+
uv_udp_t* handle,
|
|
416
|
+
uv_buf_t bufs[],
|
|
417
|
+
int bufcnt,
|
|
418
|
+
struct sockaddr* addr,
|
|
419
|
+
socklen_t addrlen,
|
|
420
|
+
uv_udp_send_cb send_cb) {
|
|
421
|
+
if (uv__udp_maybe_deferred_bind(handle, addr->sa_family))
|
|
422
|
+
return -1;
|
|
423
|
+
|
|
424
|
+
uv__req_init(handle->loop, req, UV_UDP_SEND);
|
|
425
|
+
|
|
426
|
+
assert(addrlen <= sizeof(req->addr));
|
|
427
|
+
memcpy(&req->addr, addr, addrlen);
|
|
428
|
+
req->send_cb = send_cb;
|
|
429
|
+
req->handle = handle;
|
|
430
|
+
req->bufcnt = bufcnt;
|
|
431
|
+
|
|
432
|
+
if (bufcnt <= UV_REQ_BUFSML_SIZE) {
|
|
433
|
+
req->bufs = req->bufsml;
|
|
434
|
+
}
|
|
435
|
+
else if ((req->bufs = malloc(bufcnt * sizeof(bufs[0]))) == NULL) {
|
|
436
|
+
uv__set_sys_error(handle->loop, ENOMEM);
|
|
437
|
+
return -1;
|
|
438
|
+
}
|
|
439
|
+
memcpy(req->bufs, bufs, bufcnt * sizeof(bufs[0]));
|
|
440
|
+
|
|
441
|
+
ngx_queue_insert_tail(&handle->write_queue, &req->queue);
|
|
442
|
+
|
|
443
|
+
uv__udp_start_watcher(handle,
|
|
444
|
+
&handle->write_watcher,
|
|
445
|
+
uv__udp_sendmsg,
|
|
446
|
+
UV__IO_WRITE);
|
|
447
|
+
|
|
448
|
+
return 0;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
|
|
453
|
+
memset(handle, 0, sizeof *handle);
|
|
454
|
+
|
|
455
|
+
uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
|
|
456
|
+
handle->fd = -1;
|
|
457
|
+
ngx_queue_init(&handle->write_queue);
|
|
458
|
+
ngx_queue_init(&handle->write_completed_queue);
|
|
459
|
+
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
int uv__udp_bind(uv_udp_t* handle, struct sockaddr_in addr, unsigned flags) {
|
|
465
|
+
return uv__bind(handle,
|
|
466
|
+
AF_INET,
|
|
467
|
+
(struct sockaddr*)&addr,
|
|
468
|
+
sizeof addr,
|
|
469
|
+
flags);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
int uv__udp_bind6(uv_udp_t* handle, struct sockaddr_in6 addr, unsigned flags) {
|
|
474
|
+
return uv__bind(handle,
|
|
475
|
+
AF_INET6,
|
|
476
|
+
(struct sockaddr*)&addr,
|
|
477
|
+
sizeof addr,
|
|
478
|
+
flags);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr,
|
|
483
|
+
const char* interface_addr, uv_membership membership) {
|
|
484
|
+
|
|
485
|
+
int optname;
|
|
486
|
+
struct ip_mreq mreq;
|
|
487
|
+
memset(&mreq, 0, sizeof mreq);
|
|
488
|
+
|
|
489
|
+
if (interface_addr) {
|
|
490
|
+
mreq.imr_interface.s_addr = inet_addr(interface_addr);
|
|
491
|
+
} else {
|
|
492
|
+
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
mreq.imr_multiaddr.s_addr = inet_addr(multicast_addr);
|
|
496
|
+
|
|
497
|
+
switch (membership) {
|
|
498
|
+
case UV_JOIN_GROUP:
|
|
499
|
+
optname = IP_ADD_MEMBERSHIP;
|
|
500
|
+
break;
|
|
501
|
+
case UV_LEAVE_GROUP:
|
|
502
|
+
optname = IP_DROP_MEMBERSHIP;
|
|
503
|
+
break;
|
|
504
|
+
default:
|
|
505
|
+
uv__set_sys_error(handle->loop, EFAULT);
|
|
506
|
+
return -1;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (setsockopt(handle->fd, IPPROTO_IP, optname, (void*) &mreq, sizeof mreq) == -1) {
|
|
510
|
+
uv__set_sys_error(handle->loop, errno);
|
|
511
|
+
return -1;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return 0;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
static int uv__setsockopt_maybe_char(uv_udp_t* handle, int option, int val) {
|
|
519
|
+
#if __sun
|
|
520
|
+
char arg = val;
|
|
521
|
+
#else
|
|
522
|
+
int arg = val;
|
|
523
|
+
#endif
|
|
524
|
+
|
|
525
|
+
if (val < 0 || val > 255)
|
|
526
|
+
return uv__set_sys_error(handle->loop, EINVAL);
|
|
527
|
+
|
|
528
|
+
if (setsockopt(handle->fd, IPPROTO_IP, option, &arg, sizeof(arg)))
|
|
529
|
+
return uv__set_sys_error(handle->loop, errno);
|
|
530
|
+
|
|
531
|
+
return 0;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
|
|
536
|
+
if (setsockopt(handle->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))
|
|
537
|
+
return uv__set_sys_error(handle->loop, errno);
|
|
538
|
+
|
|
539
|
+
return 0;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
|
544
|
+
if (ttl < 1 || ttl > 255)
|
|
545
|
+
return uv__set_sys_error(handle->loop, EINVAL);
|
|
546
|
+
|
|
547
|
+
if (setsockopt(handle->fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)))
|
|
548
|
+
return uv__set_sys_error(handle->loop, errno);
|
|
549
|
+
|
|
550
|
+
return 0;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
|
555
|
+
return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, ttl);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
|
560
|
+
return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, on);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name, int* namelen) {
|
|
565
|
+
socklen_t socklen;
|
|
566
|
+
int saved_errno;
|
|
567
|
+
int rv = 0;
|
|
568
|
+
|
|
569
|
+
/* Don't clobber errno. */
|
|
570
|
+
saved_errno = errno;
|
|
571
|
+
|
|
572
|
+
if (handle->fd < 0) {
|
|
573
|
+
uv__set_sys_error(handle->loop, EINVAL);
|
|
574
|
+
rv = -1;
|
|
575
|
+
goto out;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
|
579
|
+
socklen = (socklen_t)*namelen;
|
|
580
|
+
|
|
581
|
+
if (getsockname(handle->fd, name, &socklen) == -1) {
|
|
582
|
+
uv__set_sys_error(handle->loop, errno);
|
|
583
|
+
rv = -1;
|
|
584
|
+
} else {
|
|
585
|
+
*namelen = (int)socklen;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
out:
|
|
589
|
+
errno = saved_errno;
|
|
590
|
+
return rv;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
int uv_udp_send(uv_udp_send_t* req,
|
|
595
|
+
uv_udp_t* handle,
|
|
596
|
+
uv_buf_t bufs[],
|
|
597
|
+
int bufcnt,
|
|
598
|
+
struct sockaddr_in addr,
|
|
599
|
+
uv_udp_send_cb send_cb) {
|
|
600
|
+
return uv__udp_send(req,
|
|
601
|
+
handle,
|
|
602
|
+
bufs,
|
|
603
|
+
bufcnt,
|
|
604
|
+
(struct sockaddr*)&addr,
|
|
605
|
+
sizeof addr,
|
|
606
|
+
send_cb);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
int uv_udp_send6(uv_udp_send_t* req,
|
|
611
|
+
uv_udp_t* handle,
|
|
612
|
+
uv_buf_t bufs[],
|
|
613
|
+
int bufcnt,
|
|
614
|
+
struct sockaddr_in6 addr,
|
|
615
|
+
uv_udp_send_cb send_cb) {
|
|
616
|
+
return uv__udp_send(req,
|
|
617
|
+
handle,
|
|
618
|
+
bufs,
|
|
619
|
+
bufcnt,
|
|
620
|
+
(struct sockaddr*)&addr,
|
|
621
|
+
sizeof addr,
|
|
622
|
+
send_cb);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
int uv_udp_recv_start(uv_udp_t* handle,
|
|
627
|
+
uv_alloc_cb alloc_cb,
|
|
628
|
+
uv_udp_recv_cb recv_cb) {
|
|
629
|
+
if (alloc_cb == NULL || recv_cb == NULL) {
|
|
630
|
+
uv__set_artificial_error(handle->loop, UV_EINVAL);
|
|
631
|
+
return -1;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (uv__io_active(&handle->read_watcher)) {
|
|
635
|
+
uv__set_artificial_error(handle->loop, UV_EALREADY);
|
|
636
|
+
return -1;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (uv__udp_maybe_deferred_bind(handle, AF_INET))
|
|
640
|
+
return -1;
|
|
641
|
+
|
|
642
|
+
handle->alloc_cb = alloc_cb;
|
|
643
|
+
handle->recv_cb = recv_cb;
|
|
644
|
+
|
|
645
|
+
uv__udp_start_watcher(handle,
|
|
646
|
+
&handle->read_watcher,
|
|
647
|
+
uv__udp_recvmsg,
|
|
648
|
+
UV__IO_READ);
|
|
649
|
+
|
|
650
|
+
return 0;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
int uv_udp_recv_stop(uv_udp_t* handle) {
|
|
655
|
+
uv__udp_stop_watcher(handle, &handle->read_watcher);
|
|
656
|
+
handle->alloc_cb = NULL;
|
|
657
|
+
handle->recv_cb = NULL;
|
|
658
|
+
return 0;
|
|
659
|
+
}
|