passenger 5.0.8 → 5.0.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (168) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +20 -0
  5. data/CHANGELOG +21 -0
  6. data/bin/passenger-install-apache2-module +3 -1
  7. data/build/agents.rb +7 -5
  8. data/build/basics.rb +3 -3
  9. data/build/common_library.rb +52 -30
  10. data/build/cxx_tests.rb +20 -13
  11. data/build/misc.rb +5 -5
  12. data/doc/Design and Architecture.html +1 -1
  13. data/doc/Design and Architecture.txt +1 -1
  14. data/doc/Packaging.html +4 -4
  15. data/doc/Packaging.txt.md +4 -4
  16. data/doc/Users guide Apache.html +22 -9
  17. data/doc/Users guide Apache.idmap.txt +4 -2
  18. data/doc/Users guide Apache.txt +2 -0
  19. data/doc/Users guide Nginx.html +22 -9
  20. data/doc/Users guide Nginx.idmap.txt +4 -2
  21. data/doc/Users guide Nginx.txt +2 -0
  22. data/doc/Users guide Standalone.html +14 -9
  23. data/doc/Users guide Standalone.idmap.txt +4 -2
  24. data/doc/users_guide_snippets/installation.txt +10 -6
  25. data/ext/apache2/Hooks.cpp +13 -2
  26. data/ext/common/ApplicationPool2/Pool/Inspection.h +8 -3
  27. data/ext/common/BackgroundEventLoop.cpp +249 -67
  28. data/ext/common/BackgroundEventLoop.h +5 -5
  29. data/ext/common/Constants.h +1 -1
  30. data/ext/common/InstanceDirectory.h +8 -6
  31. data/ext/common/ServerKit/Context.h +8 -2
  32. data/ext/common/ServerKit/FileBufferedChannel.h +262 -226
  33. data/ext/common/ServerKit/HeaderTable.h +28 -3
  34. data/ext/common/ServerKit/HttpHeaderParser.h +37 -13
  35. data/ext/common/ServerKit/HttpServer.h +17 -1
  36. data/ext/common/ServerKit/Implementation.cpp +2 -0
  37. data/ext/common/ServerKit/Server.h +25 -28
  38. data/ext/common/Utils/IOUtils.cpp +11 -0
  39. data/ext/common/Utils/ProcessMetricsCollector.h +4 -0
  40. data/ext/common/Utils/StrIntUtils.cpp +11 -7
  41. data/ext/common/Utils/StrIntUtils.h +1 -1
  42. data/ext/common/Utils/StrIntUtilsNoStrictAliasing.cpp +21 -16
  43. data/ext/common/agents/Base.cpp +6 -0
  44. data/ext/common/agents/Base.h +2 -0
  45. data/ext/common/agents/HelperAgent/AdminServer.h +25 -25
  46. data/ext/common/agents/HelperAgent/Main.cpp +37 -12
  47. data/ext/common/agents/HelperAgent/RequestHandler.h +18 -20
  48. data/ext/common/agents/HelperAgent/RequestHandler/AppResponse.h +4 -0
  49. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +10 -6
  50. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +2 -0
  51. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +1 -1
  52. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +1 -1
  53. data/ext/common/agents/HelperAgent/RequestHandler/Utils.cpp +9 -2
  54. data/ext/common/agents/HelperAgent/ResponseCache.h +11 -11
  55. data/ext/common/agents/LoggingAgent/AdminServer.h +8 -8
  56. data/ext/common/agents/LoggingAgent/Main.cpp +6 -5
  57. data/ext/common/agents/Watchdog/AdminServer.h +13 -13
  58. data/ext/common/agents/Watchdog/Main.cpp +8 -3
  59. data/ext/libuv/.gitignore +72 -0
  60. data/ext/libuv/AUTHORS +199 -0
  61. data/ext/libuv/ChangeLog +2023 -0
  62. data/ext/libuv/LICENSE +46 -0
  63. data/ext/libuv/Makefile.am +336 -0
  64. data/ext/libuv/README.md +197 -0
  65. data/ext/libuv/checksparse.sh +233 -0
  66. data/ext/libuv/common.gypi +210 -0
  67. data/ext/libuv/configure.ac +67 -0
  68. data/ext/libuv/gyp_uv.py +96 -0
  69. data/ext/libuv/include/android-ifaddrs.h +54 -0
  70. data/ext/libuv/include/pthread-fixes.h +72 -0
  71. data/ext/libuv/include/tree.h +768 -0
  72. data/ext/libuv/include/uv-aix.h +32 -0
  73. data/ext/libuv/include/uv-bsd.h +34 -0
  74. data/ext/libuv/include/uv-darwin.h +61 -0
  75. data/ext/libuv/include/uv-errno.h +418 -0
  76. data/ext/libuv/include/uv-linux.h +34 -0
  77. data/ext/libuv/include/uv-sunos.h +44 -0
  78. data/ext/libuv/include/uv-threadpool.h +37 -0
  79. data/ext/libuv/include/uv-unix.h +383 -0
  80. data/ext/libuv/include/uv-version.h +39 -0
  81. data/ext/libuv/include/uv.h +1455 -0
  82. data/ext/libuv/libuv.pc.in +11 -0
  83. data/ext/libuv/m4/.gitignore +4 -0
  84. data/ext/libuv/m4/as_case.m4 +21 -0
  85. data/ext/libuv/m4/libuv-check-flags.m4 +319 -0
  86. data/ext/libuv/src/fs-poll.c +255 -0
  87. data/ext/libuv/src/heap-inl.h +245 -0
  88. data/ext/libuv/src/inet.c +313 -0
  89. data/ext/libuv/src/queue.h +92 -0
  90. data/ext/libuv/src/threadpool.c +303 -0
  91. data/ext/libuv/src/unix/aix.c +1240 -0
  92. data/ext/libuv/src/unix/android-ifaddrs.c +703 -0
  93. data/ext/libuv/src/unix/async.c +284 -0
  94. data/ext/libuv/src/unix/atomic-ops.h +60 -0
  95. data/ext/libuv/src/unix/core.c +985 -0
  96. data/ext/libuv/src/unix/darwin-proctitle.c +206 -0
  97. data/ext/libuv/src/unix/darwin.c +331 -0
  98. data/ext/libuv/src/unix/dl.c +83 -0
  99. data/ext/libuv/src/unix/freebsd.c +435 -0
  100. data/ext/libuv/src/unix/fs.c +1189 -0
  101. data/ext/libuv/src/unix/fsevents.c +899 -0
  102. data/ext/libuv/src/unix/getaddrinfo.c +202 -0
  103. data/ext/libuv/src/unix/getnameinfo.c +120 -0
  104. data/ext/libuv/src/unix/internal.h +314 -0
  105. data/ext/libuv/src/unix/kqueue.c +418 -0
  106. data/ext/libuv/src/unix/linux-core.c +876 -0
  107. data/ext/libuv/src/unix/linux-inotify.c +257 -0
  108. data/ext/libuv/src/unix/linux-syscalls.c +471 -0
  109. data/ext/libuv/src/unix/linux-syscalls.h +158 -0
  110. data/ext/libuv/src/unix/loop-watcher.c +63 -0
  111. data/ext/libuv/src/unix/loop.c +135 -0
  112. data/ext/libuv/src/unix/netbsd.c +368 -0
  113. data/ext/libuv/src/unix/openbsd.c +384 -0
  114. data/ext/libuv/src/unix/pipe.c +288 -0
  115. data/ext/libuv/src/unix/poll.c +113 -0
  116. data/ext/libuv/src/unix/process.c +551 -0
  117. data/ext/libuv/src/unix/proctitle.c +102 -0
  118. data/ext/libuv/src/unix/pthread-fixes.c +103 -0
  119. data/ext/libuv/src/unix/signal.c +465 -0
  120. data/ext/libuv/src/unix/spinlock.h +53 -0
  121. data/ext/libuv/src/unix/stream.c +1598 -0
  122. data/ext/libuv/src/unix/sunos.c +763 -0
  123. data/ext/libuv/src/unix/tcp.c +327 -0
  124. data/ext/libuv/src/unix/thread.c +519 -0
  125. data/ext/libuv/src/unix/timer.c +172 -0
  126. data/ext/libuv/src/unix/tty.c +265 -0
  127. data/ext/libuv/src/unix/udp.c +833 -0
  128. data/ext/libuv/src/uv-common.c +544 -0
  129. data/ext/libuv/src/uv-common.h +214 -0
  130. data/ext/libuv/src/version.c +49 -0
  131. data/ext/libuv/uv.gyp +487 -0
  132. data/ext/nginx/ContentHandler.c +21 -10
  133. data/ext/nginx/ngx_http_passenger_module.c +7 -0
  134. data/ext/oxt/implementation.cpp +9 -2
  135. data/ext/oxt/initialize.hpp +5 -1
  136. data/lib/phusion_passenger.rb +3 -3
  137. data/lib/phusion_passenger/admin_tools/instance.rb +10 -6
  138. data/lib/phusion_passenger/admin_tools/instance_registry.rb +6 -2
  139. data/lib/phusion_passenger/packaging.rb +3 -4
  140. data/lib/phusion_passenger/platform_info.rb +13 -1
  141. data/lib/phusion_passenger/platform_info/apache.rb +15 -4
  142. data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -1
  143. data/lib/phusion_passenger/rack/thread_handler_extension.rb +184 -99
  144. data/lib/phusion_passenger/request_handler/thread_handler.rb +13 -6
  145. data/lib/phusion_passenger/standalone/start_command.rb +2 -2
  146. data/resources/templates/apache2/apache_install_broken.txt.erb +2 -1
  147. metadata +99 -22
  148. metadata.gz.asc +7 -7
  149. data/ext/libeio/Changes +0 -76
  150. data/ext/libeio/LICENSE +0 -36
  151. data/ext/libeio/Makefile.am +0 -15
  152. data/ext/libeio/Makefile.in +0 -694
  153. data/ext/libeio/aclocal.m4 +0 -9418
  154. data/ext/libeio/autogen.sh +0 -3
  155. data/ext/libeio/config.guess +0 -1540
  156. data/ext/libeio/config.h.in +0 -136
  157. data/ext/libeio/config.sub +0 -1779
  158. data/ext/libeio/configure +0 -14822
  159. data/ext/libeio/configure.ac +0 -22
  160. data/ext/libeio/demo.c +0 -194
  161. data/ext/libeio/ecb.h +0 -714
  162. data/ext/libeio/eio.c +0 -2818
  163. data/ext/libeio/eio.h +0 -414
  164. data/ext/libeio/install-sh +0 -520
  165. data/ext/libeio/libeio.m4 +0 -195
  166. data/ext/libeio/ltmain.sh +0 -9636
  167. data/ext/libeio/missing +0 -376
  168. data/ext/libeio/xthread.h +0 -166
@@ -0,0 +1,172 @@
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 "heap-inl.h"
24
+
25
+ #include <assert.h>
26
+ #include <limits.h>
27
+
28
+
29
+ static int timer_less_than(const struct heap_node* ha,
30
+ const struct heap_node* hb) {
31
+ const uv_timer_t* a;
32
+ const uv_timer_t* b;
33
+
34
+ a = container_of(ha, const uv_timer_t, heap_node);
35
+ b = container_of(hb, const uv_timer_t, heap_node);
36
+
37
+ if (a->timeout < b->timeout)
38
+ return 1;
39
+ if (b->timeout < a->timeout)
40
+ return 0;
41
+
42
+ /* Compare start_id when both have the same timeout. start_id is
43
+ * allocated with loop->timer_counter in uv_timer_start().
44
+ */
45
+ if (a->start_id < b->start_id)
46
+ return 1;
47
+ if (b->start_id < a->start_id)
48
+ return 0;
49
+
50
+ return 0;
51
+ }
52
+
53
+
54
+ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
55
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
56
+ handle->timer_cb = NULL;
57
+ handle->repeat = 0;
58
+ return 0;
59
+ }
60
+
61
+
62
+ int uv_timer_start(uv_timer_t* handle,
63
+ uv_timer_cb cb,
64
+ uint64_t timeout,
65
+ uint64_t repeat) {
66
+ uint64_t clamped_timeout;
67
+
68
+ if (cb == NULL)
69
+ return -EINVAL;
70
+
71
+ if (uv__is_active(handle))
72
+ uv_timer_stop(handle);
73
+
74
+ clamped_timeout = handle->loop->time + timeout;
75
+ if (clamped_timeout < timeout)
76
+ clamped_timeout = (uint64_t) -1;
77
+
78
+ handle->timer_cb = cb;
79
+ handle->timeout = clamped_timeout;
80
+ handle->repeat = repeat;
81
+ /* start_id is the second index to be compared in uv__timer_cmp() */
82
+ handle->start_id = handle->loop->timer_counter++;
83
+
84
+ heap_insert((struct heap*) &handle->loop->timer_heap,
85
+ (struct heap_node*) &handle->heap_node,
86
+ timer_less_than);
87
+ uv__handle_start(handle);
88
+
89
+ return 0;
90
+ }
91
+
92
+
93
+ int uv_timer_stop(uv_timer_t* handle) {
94
+ if (!uv__is_active(handle))
95
+ return 0;
96
+
97
+ heap_remove((struct heap*) &handle->loop->timer_heap,
98
+ (struct heap_node*) &handle->heap_node,
99
+ timer_less_than);
100
+ uv__handle_stop(handle);
101
+
102
+ return 0;
103
+ }
104
+
105
+
106
+ int uv_timer_again(uv_timer_t* handle) {
107
+ if (handle->timer_cb == NULL)
108
+ return -EINVAL;
109
+
110
+ if (handle->repeat) {
111
+ uv_timer_stop(handle);
112
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
113
+ }
114
+
115
+ return 0;
116
+ }
117
+
118
+
119
+ void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
120
+ handle->repeat = repeat;
121
+ }
122
+
123
+
124
+ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
125
+ return handle->repeat;
126
+ }
127
+
128
+
129
+ int uv__next_timeout(const uv_loop_t* loop) {
130
+ const struct heap_node* heap_node;
131
+ const uv_timer_t* handle;
132
+ uint64_t diff;
133
+
134
+ heap_node = heap_min((const struct heap*) &loop->timer_heap);
135
+ if (heap_node == NULL)
136
+ return -1; /* block indefinitely */
137
+
138
+ handle = container_of(heap_node, const uv_timer_t, heap_node);
139
+ if (handle->timeout <= loop->time)
140
+ return 0;
141
+
142
+ diff = handle->timeout - loop->time;
143
+ if (diff > INT_MAX)
144
+ diff = INT_MAX;
145
+
146
+ return diff;
147
+ }
148
+
149
+
150
+ void uv__run_timers(uv_loop_t* loop) {
151
+ struct heap_node* heap_node;
152
+ uv_timer_t* handle;
153
+
154
+ for (;;) {
155
+ heap_node = heap_min((struct heap*) &loop->timer_heap);
156
+ if (heap_node == NULL)
157
+ break;
158
+
159
+ handle = container_of(heap_node, uv_timer_t, heap_node);
160
+ if (handle->timeout > loop->time)
161
+ break;
162
+
163
+ uv_timer_stop(handle);
164
+ uv_timer_again(handle);
165
+ handle->timer_cb(handle);
166
+ }
167
+ }
168
+
169
+
170
+ void uv__timer_close(uv_timer_t* handle) {
171
+ uv_timer_stop(handle);
172
+ }
@@ -0,0 +1,265 @@
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
+ #include "spinlock.h"
25
+
26
+ #include <assert.h>
27
+ #include <unistd.h>
28
+ #include <termios.h>
29
+ #include <errno.h>
30
+ #include <sys/ioctl.h>
31
+
32
+ static int orig_termios_fd = -1;
33
+ static struct termios orig_termios;
34
+ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
35
+
36
+
37
+ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
38
+ uv_handle_type type;
39
+ int flags;
40
+ int newfd;
41
+ int r;
42
+
43
+ /* File descriptors that refer to files cannot be monitored with epoll.
44
+ * That restriction also applies to character devices like /dev/random
45
+ * (but obviously not /dev/tty.)
46
+ */
47
+ type = uv_guess_handle(fd);
48
+ if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
49
+ return -EINVAL;
50
+
51
+ flags = 0;
52
+ newfd = -1;
53
+
54
+ uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
55
+
56
+ /* Reopen the file descriptor when it refers to a tty. This lets us put the
57
+ * tty in non-blocking mode without affecting other processes that share it
58
+ * with us.
59
+ *
60
+ * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
61
+ * affects fd 1 of `cat` because both file descriptors refer to the same
62
+ * struct file in the kernel. When we reopen our fd 0, it points to a
63
+ * different struct file, hence changing its properties doesn't affect
64
+ * other processes.
65
+ */
66
+ if (type == UV_TTY) {
67
+ r = uv__open_cloexec("/dev/tty", O_RDWR);
68
+
69
+ if (r < 0) {
70
+ /* fallback to using blocking writes */
71
+ if (!readable)
72
+ flags |= UV_STREAM_BLOCKING;
73
+ goto skip;
74
+ }
75
+
76
+ newfd = r;
77
+
78
+ r = uv__dup2_cloexec(newfd, fd);
79
+ if (r < 0 && r != -EINVAL) {
80
+ /* EINVAL means newfd == fd which could conceivably happen if another
81
+ * thread called close(fd) between our calls to isatty() and open().
82
+ * That's a rather unlikely event but let's handle it anyway.
83
+ */
84
+ uv__close(newfd);
85
+ return r;
86
+ }
87
+
88
+ fd = newfd;
89
+ }
90
+
91
+ skip:
92
+ #if defined(__APPLE__)
93
+ r = uv__stream_try_select((uv_stream_t*) tty, &fd);
94
+ if (r) {
95
+ if (newfd != -1)
96
+ uv__close(newfd);
97
+ return r;
98
+ }
99
+ #endif
100
+
101
+ if (readable)
102
+ flags |= UV_STREAM_READABLE;
103
+ else
104
+ flags |= UV_STREAM_WRITABLE;
105
+
106
+ if (!(flags & UV_STREAM_BLOCKING))
107
+ uv__nonblock(fd, 1);
108
+
109
+ uv__stream_open((uv_stream_t*) tty, fd, flags);
110
+ tty->mode = UV_TTY_MODE_NORMAL;
111
+
112
+ return 0;
113
+ }
114
+
115
+ static void uv__tty_make_raw(struct termios* tio) {
116
+ assert(tio != NULL);
117
+
118
+ #ifdef __sun
119
+ /*
120
+ * This implementation of cfmakeraw for Solaris and derivatives is taken from
121
+ * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
122
+ */
123
+ tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
124
+ IGNCR | ICRNL | IXON);
125
+ tio->c_oflag &= ~OPOST;
126
+ tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
127
+ tio->c_cflag &= ~(CSIZE | PARENB);
128
+ tio->c_cflag |= CS8;
129
+ #else
130
+ cfmakeraw(tio);
131
+ #endif /* #ifdef __sun */
132
+ }
133
+
134
+ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
135
+ struct termios tmp;
136
+ int fd;
137
+
138
+ if (tty->mode == (int) mode)
139
+ return 0;
140
+
141
+ fd = uv__stream_fd(tty);
142
+ if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
143
+ if (tcgetattr(fd, &tty->orig_termios))
144
+ return -errno;
145
+
146
+ /* This is used for uv_tty_reset_mode() */
147
+ uv_spinlock_lock(&termios_spinlock);
148
+ if (orig_termios_fd == -1) {
149
+ orig_termios = tty->orig_termios;
150
+ orig_termios_fd = fd;
151
+ }
152
+ uv_spinlock_unlock(&termios_spinlock);
153
+ }
154
+
155
+ tmp = tty->orig_termios;
156
+ switch (mode) {
157
+ case UV_TTY_MODE_NORMAL:
158
+ break;
159
+ case UV_TTY_MODE_RAW:
160
+ tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
161
+ tmp.c_oflag |= (ONLCR);
162
+ tmp.c_cflag |= (CS8);
163
+ tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
164
+ tmp.c_cc[VMIN] = 1;
165
+ tmp.c_cc[VTIME] = 0;
166
+ break;
167
+ case UV_TTY_MODE_IO:
168
+ uv__tty_make_raw(&tmp);
169
+ break;
170
+ }
171
+
172
+ /* Apply changes after draining */
173
+ if (tcsetattr(fd, TCSADRAIN, &tmp))
174
+ return -errno;
175
+
176
+ tty->mode = mode;
177
+ return 0;
178
+ }
179
+
180
+
181
+ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
182
+ struct winsize ws;
183
+
184
+ if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws))
185
+ return -errno;
186
+
187
+ *width = ws.ws_col;
188
+ *height = ws.ws_row;
189
+
190
+ return 0;
191
+ }
192
+
193
+
194
+ uv_handle_type uv_guess_handle(uv_file file) {
195
+ struct sockaddr sa;
196
+ struct stat s;
197
+ socklen_t len;
198
+ int type;
199
+
200
+ if (file < 0)
201
+ return UV_UNKNOWN_HANDLE;
202
+
203
+ if (isatty(file))
204
+ return UV_TTY;
205
+
206
+ if (fstat(file, &s))
207
+ return UV_UNKNOWN_HANDLE;
208
+
209
+ if (S_ISREG(s.st_mode))
210
+ return UV_FILE;
211
+
212
+ if (S_ISCHR(s.st_mode))
213
+ return UV_FILE; /* XXX UV_NAMED_PIPE? */
214
+
215
+ if (S_ISFIFO(s.st_mode))
216
+ return UV_NAMED_PIPE;
217
+
218
+ if (!S_ISSOCK(s.st_mode))
219
+ return UV_UNKNOWN_HANDLE;
220
+
221
+ len = sizeof(type);
222
+ if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
223
+ return UV_UNKNOWN_HANDLE;
224
+
225
+ len = sizeof(sa);
226
+ if (getsockname(file, &sa, &len))
227
+ return UV_UNKNOWN_HANDLE;
228
+
229
+ if (type == SOCK_DGRAM)
230
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
231
+ return UV_UDP;
232
+
233
+ if (type == SOCK_STREAM) {
234
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
235
+ return UV_TCP;
236
+ if (sa.sa_family == AF_UNIX)
237
+ return UV_NAMED_PIPE;
238
+ }
239
+
240
+ return UV_UNKNOWN_HANDLE;
241
+ }
242
+
243
+
244
+ /* This function is async signal-safe, meaning that it's safe to call from
245
+ * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
246
+ * critical section when the signal was raised.
247
+ */
248
+ int uv_tty_reset_mode(void) {
249
+ int saved_errno;
250
+ int err;
251
+
252
+ saved_errno = errno;
253
+ if (!uv_spinlock_trylock(&termios_spinlock))
254
+ return -EBUSY; /* In uv_tty_set_mode(). */
255
+
256
+ err = 0;
257
+ if (orig_termios_fd != -1)
258
+ if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
259
+ err = -errno;
260
+
261
+ uv_spinlock_unlock(&termios_spinlock);
262
+ errno = saved_errno;
263
+
264
+ return err;
265
+ }
@@ -0,0 +1,833 @@
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
+ #if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
32
+ # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
33
+ #endif
34
+
35
+ #if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
36
+ # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
37
+ #endif
38
+
39
+
40
+ static void uv__udp_run_completed(uv_udp_t* handle);
41
+ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
42
+ static void uv__udp_recvmsg(uv_udp_t* handle);
43
+ static void uv__udp_sendmsg(uv_udp_t* handle);
44
+ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
45
+ int domain,
46
+ unsigned int flags);
47
+
48
+
49
+ void uv__udp_close(uv_udp_t* handle) {
50
+ uv__io_close(handle->loop, &handle->io_watcher);
51
+ uv__handle_stop(handle);
52
+
53
+ if (handle->io_watcher.fd != -1) {
54
+ uv__close(handle->io_watcher.fd);
55
+ handle->io_watcher.fd = -1;
56
+ }
57
+ }
58
+
59
+
60
+ void uv__udp_finish_close(uv_udp_t* handle) {
61
+ uv_udp_send_t* req;
62
+ QUEUE* q;
63
+
64
+ assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
65
+ assert(handle->io_watcher.fd == -1);
66
+
67
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
68
+ q = QUEUE_HEAD(&handle->write_queue);
69
+ QUEUE_REMOVE(q);
70
+
71
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
72
+ req->status = -ECANCELED;
73
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
74
+ }
75
+
76
+ uv__udp_run_completed(handle);
77
+
78
+ assert(handle->send_queue_size == 0);
79
+ assert(handle->send_queue_count == 0);
80
+
81
+ /* Now tear down the handle. */
82
+ handle->recv_cb = NULL;
83
+ handle->alloc_cb = NULL;
84
+ /* but _do not_ touch close_cb */
85
+ }
86
+
87
+
88
+ static void uv__udp_run_completed(uv_udp_t* handle) {
89
+ uv_udp_send_t* req;
90
+ QUEUE* q;
91
+
92
+ while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
93
+ q = QUEUE_HEAD(&handle->write_completed_queue);
94
+ QUEUE_REMOVE(q);
95
+
96
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
97
+ uv__req_unregister(handle->loop, req);
98
+
99
+ handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
100
+ handle->send_queue_count--;
101
+
102
+ if (req->bufs != req->bufsml)
103
+ free(req->bufs);
104
+ req->bufs = NULL;
105
+
106
+ if (req->send_cb == NULL)
107
+ continue;
108
+
109
+ /* req->status >= 0 == bytes written
110
+ * req->status < 0 == errno
111
+ */
112
+ if (req->status >= 0)
113
+ req->send_cb(req, 0);
114
+ else
115
+ req->send_cb(req, req->status);
116
+ }
117
+
118
+ if (QUEUE_EMPTY(&handle->write_queue)) {
119
+ /* Pending queue and completion queue empty, stop watcher. */
120
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT);
121
+ if (!uv__io_active(&handle->io_watcher, UV__POLLIN))
122
+ uv__handle_stop(handle);
123
+ }
124
+ }
125
+
126
+
127
+ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
128
+ uv_udp_t* handle;
129
+
130
+ handle = container_of(w, uv_udp_t, io_watcher);
131
+ assert(handle->type == UV_UDP);
132
+
133
+ if (revents & UV__POLLIN)
134
+ uv__udp_recvmsg(handle);
135
+
136
+ if (revents & UV__POLLOUT) {
137
+ uv__udp_sendmsg(handle);
138
+ uv__udp_run_completed(handle);
139
+ }
140
+ }
141
+
142
+
143
+ static void uv__udp_recvmsg(uv_udp_t* handle) {
144
+ struct sockaddr_storage peer;
145
+ struct msghdr h;
146
+ ssize_t nread;
147
+ uv_buf_t buf;
148
+ int flags;
149
+ int count;
150
+
151
+ assert(handle->recv_cb != NULL);
152
+ assert(handle->alloc_cb != NULL);
153
+
154
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
155
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
156
+ */
157
+ count = 32;
158
+
159
+ memset(&h, 0, sizeof(h));
160
+ h.msg_name = &peer;
161
+
162
+ do {
163
+ handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
164
+ if (buf.len == 0) {
165
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
166
+ return;
167
+ }
168
+ assert(buf.base != NULL);
169
+
170
+ h.msg_namelen = sizeof(peer);
171
+ h.msg_iov = (void*) &buf;
172
+ h.msg_iovlen = 1;
173
+
174
+ do {
175
+ nread = recvmsg(handle->io_watcher.fd, &h, 0);
176
+ }
177
+ while (nread == -1 && errno == EINTR);
178
+
179
+ if (nread == -1) {
180
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
181
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
182
+ else
183
+ handle->recv_cb(handle, -errno, &buf, NULL, 0);
184
+ }
185
+ else {
186
+ const struct sockaddr *addr;
187
+ if (h.msg_namelen == 0)
188
+ addr = NULL;
189
+ else
190
+ addr = (const struct sockaddr*) &peer;
191
+
192
+ flags = 0;
193
+ if (h.msg_flags & MSG_TRUNC)
194
+ flags |= UV_UDP_PARTIAL;
195
+
196
+ handle->recv_cb(handle, nread, &buf, addr, flags);
197
+ }
198
+ }
199
+ /* recv_cb callback may decide to pause or close the handle */
200
+ while (nread != -1
201
+ && count-- > 0
202
+ && handle->io_watcher.fd != -1
203
+ && handle->recv_cb != NULL);
204
+ }
205
+
206
+
207
+ static void uv__udp_sendmsg(uv_udp_t* handle) {
208
+ uv_udp_send_t* req;
209
+ QUEUE* q;
210
+ struct msghdr h;
211
+ ssize_t size;
212
+
213
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
214
+ q = QUEUE_HEAD(&handle->write_queue);
215
+ assert(q != NULL);
216
+
217
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
218
+ assert(req != NULL);
219
+
220
+ memset(&h, 0, sizeof h);
221
+ h.msg_name = &req->addr;
222
+ h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
223
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
224
+ h.msg_iov = (struct iovec*) req->bufs;
225
+ h.msg_iovlen = req->nbufs;
226
+
227
+ do {
228
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
229
+ } while (size == -1 && errno == EINTR);
230
+
231
+ if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
232
+ break;
233
+
234
+ req->status = (size == -1 ? -errno : size);
235
+
236
+ /* Sending a datagram is an atomic operation: either all data
237
+ * is written or nothing is (and EMSGSIZE is raised). That is
238
+ * why we don't handle partial writes. Just pop the request
239
+ * off the write queue and onto the completed queue, done.
240
+ */
241
+ QUEUE_REMOVE(&req->queue);
242
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
243
+ uv__io_feed(handle->loop, &handle->io_watcher);
244
+ }
245
+ }
246
+
247
+
248
+ /* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
249
+ * refinements for programs that use multicast.
250
+ *
251
+ * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
252
+ * are different from the BSDs: it _shares_ the port rather than steal it
253
+ * from the current listener. While useful, it's not something we can emulate
254
+ * on other platforms so we don't enable it.
255
+ */
256
+ static int uv__set_reuse(int fd) {
257
+ int yes;
258
+
259
+ #if defined(SO_REUSEPORT) && !defined(__linux__)
260
+ yes = 1;
261
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
262
+ return -errno;
263
+ #else
264
+ yes = 1;
265
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
266
+ return -errno;
267
+ #endif
268
+
269
+ return 0;
270
+ }
271
+
272
+
273
+ int uv__udp_bind(uv_udp_t* handle,
274
+ const struct sockaddr* addr,
275
+ unsigned int addrlen,
276
+ unsigned int flags) {
277
+ int err;
278
+ int yes;
279
+ int fd;
280
+
281
+ /* Check for bad flags. */
282
+ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
283
+ return -EINVAL;
284
+
285
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
286
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
287
+ return -EINVAL;
288
+
289
+ fd = handle->io_watcher.fd;
290
+ if (fd == -1) {
291
+ err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
292
+ if (err < 0)
293
+ return err;
294
+ fd = err;
295
+ handle->io_watcher.fd = fd;
296
+ }
297
+
298
+ if (flags & UV_UDP_REUSEADDR) {
299
+ err = uv__set_reuse(fd);
300
+ if (err)
301
+ goto out;
302
+ }
303
+
304
+ if (flags & UV_UDP_IPV6ONLY) {
305
+ #ifdef IPV6_V6ONLY
306
+ yes = 1;
307
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
308
+ err = -errno;
309
+ goto out;
310
+ }
311
+ #else
312
+ err = -ENOTSUP;
313
+ goto out;
314
+ #endif
315
+ }
316
+
317
+ if (bind(fd, addr, addrlen)) {
318
+ err = -errno;
319
+ goto out;
320
+ }
321
+
322
+ if (addr->sa_family == AF_INET6)
323
+ handle->flags |= UV_HANDLE_IPV6;
324
+
325
+ return 0;
326
+
327
+ out:
328
+ uv__close(handle->io_watcher.fd);
329
+ handle->io_watcher.fd = -1;
330
+ return err;
331
+ }
332
+
333
+
334
+ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
335
+ int domain,
336
+ unsigned int flags) {
337
+ unsigned char taddr[sizeof(struct sockaddr_in6)];
338
+ socklen_t addrlen;
339
+
340
+ if (handle->io_watcher.fd != -1)
341
+ return 0;
342
+
343
+ switch (domain) {
344
+ case AF_INET:
345
+ {
346
+ struct sockaddr_in* addr = (void*)&taddr;
347
+ memset(addr, 0, sizeof *addr);
348
+ addr->sin_family = AF_INET;
349
+ addr->sin_addr.s_addr = INADDR_ANY;
350
+ addrlen = sizeof *addr;
351
+ break;
352
+ }
353
+ case AF_INET6:
354
+ {
355
+ struct sockaddr_in6* addr = (void*)&taddr;
356
+ memset(addr, 0, sizeof *addr);
357
+ addr->sin6_family = AF_INET6;
358
+ addr->sin6_addr = in6addr_any;
359
+ addrlen = sizeof *addr;
360
+ break;
361
+ }
362
+ default:
363
+ assert(0 && "unsupported address family");
364
+ abort();
365
+ }
366
+
367
+ return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags);
368
+ }
369
+
370
+
371
+ int uv__udp_send(uv_udp_send_t* req,
372
+ uv_udp_t* handle,
373
+ const uv_buf_t bufs[],
374
+ unsigned int nbufs,
375
+ const struct sockaddr* addr,
376
+ unsigned int addrlen,
377
+ uv_udp_send_cb send_cb) {
378
+ int err;
379
+ int empty_queue;
380
+
381
+ assert(nbufs > 0);
382
+
383
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
384
+ if (err)
385
+ return err;
386
+
387
+ /* It's legal for send_queue_count > 0 even when the write_queue is empty;
388
+ * it means there are error-state requests in the write_completed_queue that
389
+ * will touch up send_queue_size/count later.
390
+ */
391
+ empty_queue = (handle->send_queue_count == 0);
392
+
393
+ uv__req_init(handle->loop, req, UV_UDP_SEND);
394
+ assert(addrlen <= sizeof(req->addr));
395
+ memcpy(&req->addr, addr, addrlen);
396
+ req->send_cb = send_cb;
397
+ req->handle = handle;
398
+ req->nbufs = nbufs;
399
+
400
+ req->bufs = req->bufsml;
401
+ if (nbufs > ARRAY_SIZE(req->bufsml))
402
+ req->bufs = malloc(nbufs * sizeof(bufs[0]));
403
+
404
+ if (req->bufs == NULL)
405
+ return -ENOMEM;
406
+
407
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
408
+ handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
409
+ handle->send_queue_count++;
410
+ QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
411
+ uv__handle_start(handle);
412
+
413
+ if (empty_queue)
414
+ uv__udp_sendmsg(handle);
415
+ else
416
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
417
+
418
+ return 0;
419
+ }
420
+
421
+
422
+ int uv__udp_try_send(uv_udp_t* handle,
423
+ const uv_buf_t bufs[],
424
+ unsigned int nbufs,
425
+ const struct sockaddr* addr,
426
+ unsigned int addrlen) {
427
+ int err;
428
+ struct msghdr h;
429
+ ssize_t size;
430
+
431
+ assert(nbufs > 0);
432
+
433
+ /* already sending a message */
434
+ if (handle->send_queue_count != 0)
435
+ return -EAGAIN;
436
+
437
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
438
+ if (err)
439
+ return err;
440
+
441
+ memset(&h, 0, sizeof h);
442
+ h.msg_name = (struct sockaddr*) addr;
443
+ h.msg_namelen = addrlen;
444
+ h.msg_iov = (struct iovec*) bufs;
445
+ h.msg_iovlen = nbufs;
446
+
447
+ do {
448
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
449
+ } while (size == -1 && errno == EINTR);
450
+
451
+ if (size == -1) {
452
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
453
+ return -EAGAIN;
454
+ else
455
+ return -errno;
456
+ }
457
+
458
+ return size;
459
+ }
460
+
461
+
462
+ static int uv__udp_set_membership4(uv_udp_t* handle,
463
+ const struct sockaddr_in* multicast_addr,
464
+ const char* interface_addr,
465
+ uv_membership membership) {
466
+ struct ip_mreq mreq;
467
+ int optname;
468
+ int err;
469
+
470
+ memset(&mreq, 0, sizeof mreq);
471
+
472
+ if (interface_addr) {
473
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
474
+ if (err)
475
+ return err;
476
+ } else {
477
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
478
+ }
479
+
480
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
481
+
482
+ switch (membership) {
483
+ case UV_JOIN_GROUP:
484
+ optname = IP_ADD_MEMBERSHIP;
485
+ break;
486
+ case UV_LEAVE_GROUP:
487
+ optname = IP_DROP_MEMBERSHIP;
488
+ break;
489
+ default:
490
+ return -EINVAL;
491
+ }
492
+
493
+ if (setsockopt(handle->io_watcher.fd,
494
+ IPPROTO_IP,
495
+ optname,
496
+ &mreq,
497
+ sizeof(mreq))) {
498
+ return -errno;
499
+ }
500
+
501
+ return 0;
502
+ }
503
+
504
+
505
+ static int uv__udp_set_membership6(uv_udp_t* handle,
506
+ const struct sockaddr_in6* multicast_addr,
507
+ const char* interface_addr,
508
+ uv_membership membership) {
509
+ int optname;
510
+ struct ipv6_mreq mreq;
511
+ struct sockaddr_in6 addr6;
512
+
513
+ memset(&mreq, 0, sizeof mreq);
514
+
515
+ if (interface_addr) {
516
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
517
+ return -EINVAL;
518
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
519
+ } else {
520
+ mreq.ipv6mr_interface = 0;
521
+ }
522
+
523
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
524
+
525
+ switch (membership) {
526
+ case UV_JOIN_GROUP:
527
+ optname = IPV6_ADD_MEMBERSHIP;
528
+ break;
529
+ case UV_LEAVE_GROUP:
530
+ optname = IPV6_DROP_MEMBERSHIP;
531
+ break;
532
+ default:
533
+ return -EINVAL;
534
+ }
535
+
536
+ if (setsockopt(handle->io_watcher.fd,
537
+ IPPROTO_IPV6,
538
+ optname,
539
+ &mreq,
540
+ sizeof(mreq))) {
541
+ return -errno;
542
+ }
543
+
544
+ return 0;
545
+ }
546
+
547
+
548
+ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
549
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
550
+ handle->alloc_cb = NULL;
551
+ handle->recv_cb = NULL;
552
+ handle->send_queue_size = 0;
553
+ handle->send_queue_count = 0;
554
+ uv__io_init(&handle->io_watcher, uv__udp_io, -1);
555
+ QUEUE_INIT(&handle->write_queue);
556
+ QUEUE_INIT(&handle->write_completed_queue);
557
+ return 0;
558
+ }
559
+
560
+
561
+ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
562
+ int err;
563
+
564
+ /* Check for already active socket. */
565
+ if (handle->io_watcher.fd != -1)
566
+ return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */
567
+
568
+ err = uv__nonblock(sock, 1);
569
+ if (err)
570
+ return err;
571
+
572
+ err = uv__set_reuse(sock);
573
+ if (err)
574
+ return err;
575
+
576
+ handle->io_watcher.fd = sock;
577
+ return 0;
578
+ }
579
+
580
+
581
+ int uv_udp_set_membership(uv_udp_t* handle,
582
+ const char* multicast_addr,
583
+ const char* interface_addr,
584
+ uv_membership membership) {
585
+ int err;
586
+ struct sockaddr_in addr4;
587
+ struct sockaddr_in6 addr6;
588
+
589
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
590
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
591
+ if (err)
592
+ return err;
593
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
594
+ } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
595
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
596
+ if (err)
597
+ return err;
598
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
599
+ } else {
600
+ return -EINVAL;
601
+ }
602
+ }
603
+
604
+ static int uv__setsockopt(uv_udp_t* handle,
605
+ int option4,
606
+ int option6,
607
+ const void* val,
608
+ size_t size) {
609
+ int r;
610
+
611
+ if (handle->flags & UV_HANDLE_IPV6)
612
+ r = setsockopt(handle->io_watcher.fd,
613
+ IPPROTO_IPV6,
614
+ option6,
615
+ val,
616
+ size);
617
+ else
618
+ r = setsockopt(handle->io_watcher.fd,
619
+ IPPROTO_IP,
620
+ option4,
621
+ val,
622
+ size);
623
+ if (r)
624
+ return -errno;
625
+
626
+ return 0;
627
+ }
628
+
629
+ static int uv__setsockopt_maybe_char(uv_udp_t* handle,
630
+ int option4,
631
+ int option6,
632
+ int val) {
633
+ #if defined(__sun) || defined(_AIX)
634
+ char arg = val;
635
+ #else
636
+ int arg = val;
637
+ #endif
638
+
639
+ if (val < 0 || val > 255)
640
+ return -EINVAL;
641
+
642
+ return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
643
+ }
644
+
645
+
646
+ int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
647
+ if (setsockopt(handle->io_watcher.fd,
648
+ SOL_SOCKET,
649
+ SO_BROADCAST,
650
+ &on,
651
+ sizeof(on))) {
652
+ return -errno;
653
+ }
654
+
655
+ return 0;
656
+ }
657
+
658
+
659
+ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
660
+ if (ttl < 1 || ttl > 255)
661
+ return -EINVAL;
662
+
663
+ /*
664
+ * On Solaris and derivatives such as SmartOS, the length of socket options
665
+ * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
666
+ * so hardcode the size of these options on this platform,
667
+ * and use the general uv__setsockopt_maybe_char call on other platforms.
668
+ */
669
+ #if defined(__sun)
670
+ return uv__setsockopt(handle,
671
+ IP_TTL,
672
+ IPV6_UNICAST_HOPS,
673
+ &ttl,
674
+ sizeof(ttl));
675
+ #endif /* defined(__sun) */
676
+
677
+ return uv__setsockopt_maybe_char(handle,
678
+ IP_TTL,
679
+ IPV6_UNICAST_HOPS,
680
+ ttl);
681
+ }
682
+
683
+
684
+ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
685
+ /*
686
+ * On Solaris and derivatives such as SmartOS, the length of socket options
687
+ * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
688
+ * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
689
+ * and use the general uv__setsockopt_maybe_char call otherwise.
690
+ */
691
+ #if defined(__sun)
692
+ if (handle->flags & UV_HANDLE_IPV6)
693
+ return uv__setsockopt(handle,
694
+ IP_MULTICAST_TTL,
695
+ IPV6_MULTICAST_HOPS,
696
+ &ttl,
697
+ sizeof(ttl));
698
+ #endif /* defined(__sun) */
699
+
700
+ return uv__setsockopt_maybe_char(handle,
701
+ IP_MULTICAST_TTL,
702
+ IPV6_MULTICAST_HOPS,
703
+ ttl);
704
+ }
705
+
706
+
707
+ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
708
+ /*
709
+ * On Solaris and derivatives such as SmartOS, the length of socket options
710
+ * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
711
+ * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
712
+ * and use the general uv__setsockopt_maybe_char call otherwise.
713
+ */
714
+ #if defined(__sun)
715
+ if (handle->flags & UV_HANDLE_IPV6)
716
+ return uv__setsockopt(handle,
717
+ IP_MULTICAST_LOOP,
718
+ IPV6_MULTICAST_LOOP,
719
+ &on,
720
+ sizeof(on));
721
+ #endif /* defined(__sun) */
722
+
723
+ return uv__setsockopt_maybe_char(handle,
724
+ IP_MULTICAST_LOOP,
725
+ IPV6_MULTICAST_LOOP,
726
+ on);
727
+ }
728
+
729
+ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
730
+ struct sockaddr_storage addr_st;
731
+ struct sockaddr_in* addr4;
732
+ struct sockaddr_in6* addr6;
733
+
734
+ addr4 = (struct sockaddr_in*) &addr_st;
735
+ addr6 = (struct sockaddr_in6*) &addr_st;
736
+
737
+ if (!interface_addr) {
738
+ memset(&addr_st, 0, sizeof addr_st);
739
+ if (handle->flags & UV_HANDLE_IPV6) {
740
+ addr_st.ss_family = AF_INET6;
741
+ addr6->sin6_scope_id = 0;
742
+ } else {
743
+ addr_st.ss_family = AF_INET;
744
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
745
+ }
746
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
747
+ /* nothing, address was parsed */
748
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
749
+ /* nothing, address was parsed */
750
+ } else {
751
+ return -EINVAL;
752
+ }
753
+
754
+ if (addr_st.ss_family == AF_INET) {
755
+ if (setsockopt(handle->io_watcher.fd,
756
+ IPPROTO_IP,
757
+ IP_MULTICAST_IF,
758
+ (void*) &addr4->sin_addr,
759
+ sizeof(addr4->sin_addr)) == -1) {
760
+ return -errno;
761
+ }
762
+ } else if (addr_st.ss_family == AF_INET6) {
763
+ if (setsockopt(handle->io_watcher.fd,
764
+ IPPROTO_IPV6,
765
+ IPV6_MULTICAST_IF,
766
+ &addr6->sin6_scope_id,
767
+ sizeof(addr6->sin6_scope_id)) == -1) {
768
+ return -errno;
769
+ }
770
+ } else {
771
+ assert(0 && "unexpected address family");
772
+ abort();
773
+ }
774
+
775
+ return 0;
776
+ }
777
+
778
+
779
+ int uv_udp_getsockname(const uv_udp_t* handle,
780
+ struct sockaddr* name,
781
+ int* namelen) {
782
+ socklen_t socklen;
783
+
784
+ if (handle->io_watcher.fd == -1)
785
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
786
+
787
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
788
+ socklen = (socklen_t) *namelen;
789
+
790
+ if (getsockname(handle->io_watcher.fd, name, &socklen))
791
+ return -errno;
792
+
793
+ *namelen = (int) socklen;
794
+ return 0;
795
+ }
796
+
797
+
798
+ int uv__udp_recv_start(uv_udp_t* handle,
799
+ uv_alloc_cb alloc_cb,
800
+ uv_udp_recv_cb recv_cb) {
801
+ int err;
802
+
803
+ if (alloc_cb == NULL || recv_cb == NULL)
804
+ return -EINVAL;
805
+
806
+ if (uv__io_active(&handle->io_watcher, UV__POLLIN))
807
+ return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */
808
+
809
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
810
+ if (err)
811
+ return err;
812
+
813
+ handle->alloc_cb = alloc_cb;
814
+ handle->recv_cb = recv_cb;
815
+
816
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
817
+ uv__handle_start(handle);
818
+
819
+ return 0;
820
+ }
821
+
822
+
823
+ int uv__udp_recv_stop(uv_udp_t* handle) {
824
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN);
825
+
826
+ if (!uv__io_active(&handle->io_watcher, UV__POLLOUT))
827
+ uv__handle_stop(handle);
828
+
829
+ handle->alloc_cb = NULL;
830
+ handle->recv_cb = NULL;
831
+
832
+ return 0;
833
+ }