foolio 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (261) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +21 -0
  6. data/examples/timer.rb +20 -0
  7. data/ext/foolio/extconf.rb +34 -0
  8. data/ext/foolio/foolio_ext.c +921 -0
  9. data/ext/foolio/gen.rb +50 -0
  10. data/ext/foolio/make_table.rb +12 -0
  11. data/ext/foolio/templ +243 -0
  12. data/ext/libuv/.gitignore +33 -0
  13. data/ext/libuv/.mailmap +13 -0
  14. data/ext/libuv/.travis.yml +9 -0
  15. data/ext/libuv/AUTHORS +61 -0
  16. data/ext/libuv/LICENSE +44 -0
  17. data/ext/libuv/Makefile +71 -0
  18. data/ext/libuv/README.md +90 -0
  19. data/ext/libuv/common.gypi +178 -0
  20. data/ext/libuv/gyp_uv +73 -0
  21. data/ext/libuv/include/uv-private/eio.h +403 -0
  22. data/ext/libuv/include/uv-private/ev.h +838 -0
  23. data/ext/libuv/include/uv-private/ngx-queue.h +108 -0
  24. data/ext/libuv/include/uv-private/tree.h +768 -0
  25. data/ext/libuv/include/uv-private/uv-unix.h +324 -0
  26. data/ext/libuv/include/uv-private/uv-win.h +517 -0
  27. data/ext/libuv/include/uv.h +1838 -0
  28. data/ext/libuv/src/fs-poll.c +235 -0
  29. data/ext/libuv/src/inet.c +293 -0
  30. data/ext/libuv/src/unix/async.c +148 -0
  31. data/ext/libuv/src/unix/core.c +696 -0
  32. data/ext/libuv/src/unix/cygwin.c +83 -0
  33. data/ext/libuv/src/unix/darwin.c +342 -0
  34. data/ext/libuv/src/unix/dl.c +83 -0
  35. data/ext/libuv/src/unix/eio/Changes +63 -0
  36. data/ext/libuv/src/unix/eio/LICENSE +36 -0
  37. data/ext/libuv/src/unix/eio/Makefile.am +15 -0
  38. data/ext/libuv/src/unix/eio/aclocal.m4 +8957 -0
  39. data/ext/libuv/src/unix/eio/autogen.sh +3 -0
  40. data/ext/libuv/src/unix/eio/config.h.in +86 -0
  41. data/ext/libuv/src/unix/eio/config_cygwin.h +80 -0
  42. data/ext/libuv/src/unix/eio/config_darwin.h +141 -0
  43. data/ext/libuv/src/unix/eio/config_freebsd.h +81 -0
  44. data/ext/libuv/src/unix/eio/config_linux.h +94 -0
  45. data/ext/libuv/src/unix/eio/config_netbsd.h +81 -0
  46. data/ext/libuv/src/unix/eio/config_openbsd.h +137 -0
  47. data/ext/libuv/src/unix/eio/config_sunos.h +84 -0
  48. data/ext/libuv/src/unix/eio/configure.ac +22 -0
  49. data/ext/libuv/src/unix/eio/demo.c +194 -0
  50. data/ext/libuv/src/unix/eio/ecb.h +370 -0
  51. data/ext/libuv/src/unix/eio/eio.3 +3428 -0
  52. data/ext/libuv/src/unix/eio/eio.c +2593 -0
  53. data/ext/libuv/src/unix/eio/eio.pod +969 -0
  54. data/ext/libuv/src/unix/eio/libeio.m4 +195 -0
  55. data/ext/libuv/src/unix/eio/xthread.h +164 -0
  56. data/ext/libuv/src/unix/error.c +105 -0
  57. data/ext/libuv/src/unix/ev/Changes +388 -0
  58. data/ext/libuv/src/unix/ev/LICENSE +36 -0
  59. data/ext/libuv/src/unix/ev/Makefile.am +18 -0
  60. data/ext/libuv/src/unix/ev/Makefile.in +771 -0
  61. data/ext/libuv/src/unix/ev/README +58 -0
  62. data/ext/libuv/src/unix/ev/aclocal.m4 +8957 -0
  63. data/ext/libuv/src/unix/ev/autogen.sh +6 -0
  64. data/ext/libuv/src/unix/ev/config.guess +1526 -0
  65. data/ext/libuv/src/unix/ev/config.h.in +125 -0
  66. data/ext/libuv/src/unix/ev/config.sub +1658 -0
  67. data/ext/libuv/src/unix/ev/config_cygwin.h +123 -0
  68. data/ext/libuv/src/unix/ev/config_darwin.h +122 -0
  69. data/ext/libuv/src/unix/ev/config_freebsd.h +120 -0
  70. data/ext/libuv/src/unix/ev/config_linux.h +141 -0
  71. data/ext/libuv/src/unix/ev/config_netbsd.h +120 -0
  72. data/ext/libuv/src/unix/ev/config_openbsd.h +126 -0
  73. data/ext/libuv/src/unix/ev/config_sunos.h +122 -0
  74. data/ext/libuv/src/unix/ev/configure +13037 -0
  75. data/ext/libuv/src/unix/ev/configure.ac +18 -0
  76. data/ext/libuv/src/unix/ev/depcomp +630 -0
  77. data/ext/libuv/src/unix/ev/ev++.h +816 -0
  78. data/ext/libuv/src/unix/ev/ev.3 +5311 -0
  79. data/ext/libuv/src/unix/ev/ev.c +3925 -0
  80. data/ext/libuv/src/unix/ev/ev.pod +5243 -0
  81. data/ext/libuv/src/unix/ev/ev_epoll.c +266 -0
  82. data/ext/libuv/src/unix/ev/ev_kqueue.c +235 -0
  83. data/ext/libuv/src/unix/ev/ev_poll.c +148 -0
  84. data/ext/libuv/src/unix/ev/ev_port.c +179 -0
  85. data/ext/libuv/src/unix/ev/ev_select.c +310 -0
  86. data/ext/libuv/src/unix/ev/ev_vars.h +203 -0
  87. data/ext/libuv/src/unix/ev/ev_win32.c +153 -0
  88. data/ext/libuv/src/unix/ev/ev_wrap.h +196 -0
  89. data/ext/libuv/src/unix/ev/event.c +402 -0
  90. data/ext/libuv/src/unix/ev/event.h +170 -0
  91. data/ext/libuv/src/unix/ev/install-sh +294 -0
  92. data/ext/libuv/src/unix/ev/libev.m4 +39 -0
  93. data/ext/libuv/src/unix/ev/ltmain.sh +8413 -0
  94. data/ext/libuv/src/unix/ev/missing +336 -0
  95. data/ext/libuv/src/unix/ev/mkinstalldirs +111 -0
  96. data/ext/libuv/src/unix/freebsd.c +326 -0
  97. data/ext/libuv/src/unix/fs.c +739 -0
  98. data/ext/libuv/src/unix/internal.h +188 -0
  99. data/ext/libuv/src/unix/kqueue.c +120 -0
  100. data/ext/libuv/src/unix/linux/inotify.c +239 -0
  101. data/ext/libuv/src/unix/linux/linux-core.c +557 -0
  102. data/ext/libuv/src/unix/linux/syscalls.c +388 -0
  103. data/ext/libuv/src/unix/linux/syscalls.h +124 -0
  104. data/ext/libuv/src/unix/loop-watcher.c +62 -0
  105. data/ext/libuv/src/unix/loop.c +94 -0
  106. data/ext/libuv/src/unix/netbsd.c +108 -0
  107. data/ext/libuv/src/unix/openbsd.c +295 -0
  108. data/ext/libuv/src/unix/pipe.c +259 -0
  109. data/ext/libuv/src/unix/poll.c +114 -0
  110. data/ext/libuv/src/unix/process.c +495 -0
  111. data/ext/libuv/src/unix/signal.c +269 -0
  112. data/ext/libuv/src/unix/stream.c +990 -0
  113. data/ext/libuv/src/unix/sunos.c +481 -0
  114. data/ext/libuv/src/unix/tcp.c +393 -0
  115. data/ext/libuv/src/unix/thread.c +251 -0
  116. data/ext/libuv/src/unix/timer.c +136 -0
  117. data/ext/libuv/src/unix/tty.c +145 -0
  118. data/ext/libuv/src/unix/udp.c +659 -0
  119. data/ext/libuv/src/unix/uv-eio.c +107 -0
  120. data/ext/libuv/src/unix/uv-eio.h +13 -0
  121. data/ext/libuv/src/uv-common.c +380 -0
  122. data/ext/libuv/src/uv-common.h +170 -0
  123. data/ext/libuv/src/win/async.c +100 -0
  124. data/ext/libuv/src/win/atomicops-inl.h +56 -0
  125. data/ext/libuv/src/win/core.c +278 -0
  126. data/ext/libuv/src/win/dl.c +86 -0
  127. data/ext/libuv/src/win/error.c +155 -0
  128. data/ext/libuv/src/win/fs-event.c +510 -0
  129. data/ext/libuv/src/win/fs.c +1948 -0
  130. data/ext/libuv/src/win/getaddrinfo.c +365 -0
  131. data/ext/libuv/src/win/handle-inl.h +149 -0
  132. data/ext/libuv/src/win/handle.c +154 -0
  133. data/ext/libuv/src/win/internal.h +343 -0
  134. data/ext/libuv/src/win/loop-watcher.c +122 -0
  135. data/ext/libuv/src/win/pipe.c +1672 -0
  136. data/ext/libuv/src/win/poll.c +616 -0
  137. data/ext/libuv/src/win/process-stdio.c +500 -0
  138. data/ext/libuv/src/win/process.c +1013 -0
  139. data/ext/libuv/src/win/req-inl.h +220 -0
  140. data/ext/libuv/src/win/req.c +25 -0
  141. data/ext/libuv/src/win/signal.c +57 -0
  142. data/ext/libuv/src/win/stream-inl.h +67 -0
  143. data/ext/libuv/src/win/stream.c +167 -0
  144. data/ext/libuv/src/win/tcp.c +1394 -0
  145. data/ext/libuv/src/win/thread.c +372 -0
  146. data/ext/libuv/src/win/threadpool.c +74 -0
  147. data/ext/libuv/src/win/timer.c +224 -0
  148. data/ext/libuv/src/win/tty.c +1799 -0
  149. data/ext/libuv/src/win/udp.c +716 -0
  150. data/ext/libuv/src/win/util.c +864 -0
  151. data/ext/libuv/src/win/winapi.c +132 -0
  152. data/ext/libuv/src/win/winapi.h +4452 -0
  153. data/ext/libuv/src/win/winsock.c +557 -0
  154. data/ext/libuv/src/win/winsock.h +171 -0
  155. data/ext/libuv/test/benchmark-async-pummel.c +97 -0
  156. data/ext/libuv/test/benchmark-async.c +137 -0
  157. data/ext/libuv/test/benchmark-fs-stat.c +135 -0
  158. data/ext/libuv/test/benchmark-getaddrinfo.c +94 -0
  159. data/ext/libuv/test/benchmark-list.h +127 -0
  160. data/ext/libuv/test/benchmark-loop-count.c +88 -0
  161. data/ext/libuv/test/benchmark-million-timers.c +65 -0
  162. data/ext/libuv/test/benchmark-ping-pongs.c +213 -0
  163. data/ext/libuv/test/benchmark-pound.c +324 -0
  164. data/ext/libuv/test/benchmark-pump.c +462 -0
  165. data/ext/libuv/test/benchmark-sizes.c +44 -0
  166. data/ext/libuv/test/benchmark-spawn.c +162 -0
  167. data/ext/libuv/test/benchmark-tcp-write-batch.c +140 -0
  168. data/ext/libuv/test/benchmark-thread.c +64 -0
  169. data/ext/libuv/test/benchmark-udp-packet-storm.c +247 -0
  170. data/ext/libuv/test/blackhole-server.c +118 -0
  171. data/ext/libuv/test/dns-server.c +321 -0
  172. data/ext/libuv/test/echo-server.c +378 -0
  173. data/ext/libuv/test/fixtures/empty_file +0 -0
  174. data/ext/libuv/test/fixtures/load_error.node +1 -0
  175. data/ext/libuv/test/run-benchmarks.c +64 -0
  176. data/ext/libuv/test/run-tests.c +138 -0
  177. data/ext/libuv/test/runner-unix.c +295 -0
  178. data/ext/libuv/test/runner-unix.h +36 -0
  179. data/ext/libuv/test/runner-win.c +285 -0
  180. data/ext/libuv/test/runner-win.h +42 -0
  181. data/ext/libuv/test/runner.c +355 -0
  182. data/ext/libuv/test/runner.h +159 -0
  183. data/ext/libuv/test/task.h +112 -0
  184. data/ext/libuv/test/test-async.c +118 -0
  185. data/ext/libuv/test/test-callback-order.c +76 -0
  186. data/ext/libuv/test/test-callback-stack.c +203 -0
  187. data/ext/libuv/test/test-connection-fail.c +148 -0
  188. data/ext/libuv/test/test-cwd-and-chdir.c +64 -0
  189. data/ext/libuv/test/test-delayed-accept.c +188 -0
  190. data/ext/libuv/test/test-dlerror.c +58 -0
  191. data/ext/libuv/test/test-error.c +59 -0
  192. data/ext/libuv/test/test-fail-always.c +29 -0
  193. data/ext/libuv/test/test-fs-event.c +474 -0
  194. data/ext/libuv/test/test-fs-poll.c +146 -0
  195. data/ext/libuv/test/test-fs.c +1843 -0
  196. data/ext/libuv/test/test-get-currentexe.c +63 -0
  197. data/ext/libuv/test/test-get-loadavg.c +36 -0
  198. data/ext/libuv/test/test-get-memory.c +38 -0
  199. data/ext/libuv/test/test-getaddrinfo.c +122 -0
  200. data/ext/libuv/test/test-getsockname.c +342 -0
  201. data/ext/libuv/test/test-hrtime.c +54 -0
  202. data/ext/libuv/test/test-idle.c +81 -0
  203. data/ext/libuv/test/test-ipc-send-recv.c +209 -0
  204. data/ext/libuv/test/test-ipc.c +620 -0
  205. data/ext/libuv/test/test-list.h +427 -0
  206. data/ext/libuv/test/test-loop-handles.c +336 -0
  207. data/ext/libuv/test/test-multiple-listen.c +102 -0
  208. data/ext/libuv/test/test-mutexes.c +63 -0
  209. data/ext/libuv/test/test-pass-always.c +28 -0
  210. data/ext/libuv/test/test-ping-pong.c +253 -0
  211. data/ext/libuv/test/test-pipe-bind-error.c +140 -0
  212. data/ext/libuv/test/test-pipe-connect-error.c +96 -0
  213. data/ext/libuv/test/test-platform-output.c +87 -0
  214. data/ext/libuv/test/test-poll-close.c +72 -0
  215. data/ext/libuv/test/test-poll.c +573 -0
  216. data/ext/libuv/test/test-process-title.c +49 -0
  217. data/ext/libuv/test/test-ref.c +338 -0
  218. data/ext/libuv/test/test-run-once.c +48 -0
  219. data/ext/libuv/test/test-semaphore.c +111 -0
  220. data/ext/libuv/test/test-shutdown-close.c +103 -0
  221. data/ext/libuv/test/test-shutdown-eof.c +183 -0
  222. data/ext/libuv/test/test-signal.c +162 -0
  223. data/ext/libuv/test/test-spawn.c +863 -0
  224. data/ext/libuv/test/test-stdio-over-pipes.c +246 -0
  225. data/ext/libuv/test/test-tcp-bind-error.c +191 -0
  226. data/ext/libuv/test/test-tcp-bind6-error.c +154 -0
  227. data/ext/libuv/test/test-tcp-close-while-connecting.c +80 -0
  228. data/ext/libuv/test/test-tcp-close.c +129 -0
  229. data/ext/libuv/test/test-tcp-connect-error-after-write.c +95 -0
  230. data/ext/libuv/test/test-tcp-connect-error.c +70 -0
  231. data/ext/libuv/test/test-tcp-connect-timeout.c +85 -0
  232. data/ext/libuv/test/test-tcp-connect6-error.c +68 -0
  233. data/ext/libuv/test/test-tcp-flags.c +51 -0
  234. data/ext/libuv/test/test-tcp-shutdown-after-write.c +131 -0
  235. data/ext/libuv/test/test-tcp-unexpected-read.c +113 -0
  236. data/ext/libuv/test/test-tcp-write-error.c +168 -0
  237. data/ext/libuv/test/test-tcp-write-to-half-open-connection.c +135 -0
  238. data/ext/libuv/test/test-tcp-writealot.c +170 -0
  239. data/ext/libuv/test/test-thread.c +183 -0
  240. data/ext/libuv/test/test-threadpool.c +57 -0
  241. data/ext/libuv/test/test-timer-again.c +141 -0
  242. data/ext/libuv/test/test-timer.c +152 -0
  243. data/ext/libuv/test/test-tty.c +110 -0
  244. data/ext/libuv/test/test-udp-dgram-too-big.c +86 -0
  245. data/ext/libuv/test/test-udp-ipv6.c +156 -0
  246. data/ext/libuv/test/test-udp-multicast-join.c +139 -0
  247. data/ext/libuv/test/test-udp-multicast-ttl.c +86 -0
  248. data/ext/libuv/test/test-udp-options.c +86 -0
  249. data/ext/libuv/test/test-udp-send-and-recv.c +208 -0
  250. data/ext/libuv/test/test-util.c +97 -0
  251. data/ext/libuv/test/test-walk-handles.c +77 -0
  252. data/ext/libuv/uv.gyp +375 -0
  253. data/ext/libuv/vcbuild.bat +105 -0
  254. data/foolio.gemspec +18 -0
  255. data/lib/foolio.rb +9 -0
  256. data/lib/foolio/handle.rb +27 -0
  257. data/lib/foolio/listener.rb +26 -0
  258. data/lib/foolio/loop.rb +79 -0
  259. data/lib/foolio/stream.rb +109 -0
  260. data/lib/foolio/version.rb +3 -0
  261. metadata +309 -0
@@ -0,0 +1,122 @@
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 <assert.h>
23
+
24
+ #include "uv.h"
25
+ #include "internal.h"
26
+ #include "handle-inl.h"
27
+
28
+
29
+ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
30
+ if (handle->flags & UV_HANDLE_CLOSING) {
31
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
32
+ handle->flags |= UV_HANDLE_CLOSED;
33
+ uv__handle_stop(handle);
34
+ uv__handle_close(handle);
35
+ }
36
+ }
37
+
38
+
39
+ #define UV_LOOP_WATCHER_DEFINE(name, NAME) \
40
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
41
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
42
+ \
43
+ return 0; \
44
+ } \
45
+ \
46
+ \
47
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
48
+ uv_loop_t* loop = handle->loop; \
49
+ uv_##name##_t* old_head; \
50
+ \
51
+ assert(handle->type == UV_##NAME); \
52
+ \
53
+ if (handle->flags & UV_HANDLE_ACTIVE) \
54
+ return 0; \
55
+ \
56
+ old_head = loop->name##_handles; \
57
+ \
58
+ handle->name##_next = old_head; \
59
+ handle->name##_prev = NULL; \
60
+ \
61
+ if (old_head) { \
62
+ old_head->name##_prev = handle; \
63
+ } \
64
+ \
65
+ loop->name##_handles = handle; \
66
+ \
67
+ handle->name##_cb = cb; \
68
+ handle->flags |= UV_HANDLE_ACTIVE; \
69
+ uv__handle_start(handle); \
70
+ \
71
+ return 0; \
72
+ } \
73
+ \
74
+ \
75
+ int uv_##name##_stop(uv_##name##_t* handle) { \
76
+ uv_loop_t* loop = handle->loop; \
77
+ \
78
+ assert(handle->type == UV_##NAME); \
79
+ \
80
+ if (!(handle->flags & UV_HANDLE_ACTIVE)) \
81
+ return 0; \
82
+ \
83
+ /* Update loop head if needed */ \
84
+ if (loop->name##_handles == handle) { \
85
+ loop->name##_handles = handle->name##_next; \
86
+ } \
87
+ \
88
+ /* Update the iterator-next pointer of needed */ \
89
+ if (loop->next_##name##_handle == handle) { \
90
+ loop->next_##name##_handle = handle->name##_next; \
91
+ } \
92
+ \
93
+ if (handle->name##_prev) { \
94
+ handle->name##_prev->name##_next = handle->name##_next; \
95
+ } \
96
+ if (handle->name##_next) { \
97
+ handle->name##_next->name##_prev = handle->name##_prev; \
98
+ } \
99
+ \
100
+ handle->flags &= ~UV_HANDLE_ACTIVE; \
101
+ uv__handle_stop(handle); \
102
+ \
103
+ return 0; \
104
+ } \
105
+ \
106
+ \
107
+ void uv_##name##_invoke(uv_loop_t* loop) { \
108
+ uv_##name##_t* handle; \
109
+ \
110
+ (loop)->next_##name##_handle = (loop)->name##_handles; \
111
+ \
112
+ while ((loop)->next_##name##_handle != NULL) { \
113
+ handle = (loop)->next_##name##_handle; \
114
+ (loop)->next_##name##_handle = handle->name##_next; \
115
+ \
116
+ handle->name##_cb(handle, 0); \
117
+ } \
118
+ }
119
+
120
+ UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
121
+ UV_LOOP_WATCHER_DEFINE(check, CHECK)
122
+ UV_LOOP_WATCHER_DEFINE(idle, IDLE)
@@ -0,0 +1,1672 @@
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 <assert.h>
23
+ #include <io.h>
24
+ #include <string.h>
25
+ #include <stdio.h>
26
+
27
+ #include "uv.h"
28
+ #include "internal.h"
29
+ #include "handle-inl.h"
30
+ #include "stream-inl.h"
31
+ #include "req-inl.h"
32
+
33
+
34
+ /* A zero-size buffer for use by uv_pipe_read */
35
+ static char uv_zero_[] = "";
36
+
37
+ /* Null uv_buf_t */
38
+ static const uv_buf_t uv_null_buf_ = { 0, NULL };
39
+
40
+ /* The timeout that the pipe will wait for the remote end to write data */
41
+ /* when the local ends wants to shut it down. */
42
+ static const int64_t eof_timeout = 50; /* ms */
43
+
44
+ static const int default_pending_pipe_instances = 4;
45
+
46
+ /* IPC protocol flags. */
47
+ #define UV_IPC_RAW_DATA 0x0001
48
+ #define UV_IPC_TCP_SERVER 0x0002
49
+ #define UV_IPC_TCP_CONNECTION 0x0004
50
+
51
+ /* IPC frame header. */
52
+ typedef struct {
53
+ int flags;
54
+ uint64_t raw_data_length;
55
+ } uv_ipc_frame_header_t;
56
+
57
+ /* IPC frame, which contains an imported TCP socket stream. */
58
+ typedef struct {
59
+ uv_ipc_frame_header_t header;
60
+ WSAPROTOCOL_INFOW socket_info;
61
+ } uv_ipc_frame_uv_stream;
62
+
63
+ static void eof_timer_init(uv_pipe_t* pipe);
64
+ static void eof_timer_start(uv_pipe_t* pipe);
65
+ static void eof_timer_stop(uv_pipe_t* pipe);
66
+ static void eof_timer_cb(uv_timer_t* timer, int status);
67
+ static void eof_timer_destroy(uv_pipe_t* pipe);
68
+ static void eof_timer_close_cb(uv_handle_t* handle);
69
+
70
+
71
+ static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
72
+ _snprintf(name, size, "\\\\.\\pipe\\uv\\%p-%d", ptr, GetCurrentProcessId());
73
+ }
74
+
75
+
76
+ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
77
+ uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
78
+
79
+ handle->reqs_pending = 0;
80
+ handle->handle = INVALID_HANDLE_VALUE;
81
+ handle->name = NULL;
82
+ handle->ipc_pid = 0;
83
+ handle->remaining_ipc_rawdata_bytes = 0;
84
+ handle->pending_ipc_info.socket_info = NULL;
85
+ handle->pending_ipc_info.tcp_connection = 0;
86
+ handle->ipc = ipc;
87
+ handle->non_overlapped_writes_tail = NULL;
88
+
89
+ uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req);
90
+
91
+ return 0;
92
+ }
93
+
94
+
95
+ static void uv_pipe_connection_init(uv_pipe_t* handle) {
96
+ uv_connection_init((uv_stream_t*) handle);
97
+ handle->read_req.data = handle;
98
+ handle->eof_timer = NULL;
99
+ }
100
+
101
+
102
+ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
103
+ HANDLE pipeHandle;
104
+
105
+ /*
106
+ * Assume that we have a duplex pipe first, so attempt to
107
+ * connect with GENERIC_READ | GENERIC_WRITE.
108
+ */
109
+ pipeHandle = CreateFileW(name,
110
+ GENERIC_READ | GENERIC_WRITE,
111
+ 0,
112
+ NULL,
113
+ OPEN_EXISTING,
114
+ FILE_FLAG_OVERLAPPED,
115
+ NULL);
116
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
117
+ *duplex_flags = 0;
118
+ return pipeHandle;
119
+ }
120
+
121
+ /*
122
+ * If the pipe is not duplex CreateFileW fails with
123
+ * ERROR_ACCESS_DENIED. In that case try to connect
124
+ * as a read-only or write-only.
125
+ */
126
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
127
+ pipeHandle = CreateFileW(name,
128
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
129
+ 0,
130
+ NULL,
131
+ OPEN_EXISTING,
132
+ FILE_FLAG_OVERLAPPED,
133
+ NULL);
134
+
135
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
136
+ *duplex_flags = UV_HANDLE_SHUTTING;
137
+ return pipeHandle;
138
+ }
139
+ }
140
+
141
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
142
+ pipeHandle = CreateFileW(name,
143
+ GENERIC_WRITE | FILE_READ_ATTRIBUTES,
144
+ 0,
145
+ NULL,
146
+ OPEN_EXISTING,
147
+ FILE_FLAG_OVERLAPPED,
148
+ NULL);
149
+
150
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
151
+ *duplex_flags = UV_HANDLE_EOF;
152
+ return pipeHandle;
153
+ }
154
+ }
155
+
156
+ return INVALID_HANDLE_VALUE;
157
+ }
158
+
159
+
160
+ uv_err_t uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
161
+ char* name, size_t nameSize) {
162
+ HANDLE pipeHandle;
163
+ int errorno;
164
+ uv_err_t err;
165
+ char* ptr = (char*)handle;
166
+
167
+ for (;;) {
168
+ uv_unique_pipe_name(ptr, name, nameSize);
169
+
170
+ pipeHandle = CreateNamedPipeA(name,
171
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
172
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
173
+ NULL);
174
+
175
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
176
+ /* No name collisions. We're done. */
177
+ break;
178
+ }
179
+
180
+ errorno = GetLastError();
181
+ if (errorno != ERROR_PIPE_BUSY && errorno != ERROR_ACCESS_DENIED) {
182
+ err = uv__new_sys_error(errorno);
183
+ goto error;
184
+ }
185
+
186
+ /* Pipe name collision. Increment the pointer and try again. */
187
+ ptr++;
188
+ }
189
+
190
+ if (CreateIoCompletionPort(pipeHandle,
191
+ loop->iocp,
192
+ (ULONG_PTR)handle,
193
+ 0) == NULL) {
194
+ err = uv__new_sys_error(GetLastError());
195
+ goto error;
196
+ }
197
+
198
+ uv_pipe_connection_init(handle);
199
+ handle->handle = pipeHandle;
200
+
201
+ return uv_ok_;
202
+
203
+ error:
204
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
205
+ CloseHandle(pipeHandle);
206
+ }
207
+
208
+ return err;
209
+ }
210
+
211
+
212
+ static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle,
213
+ HANDLE pipeHandle, DWORD duplex_flags) {
214
+ NTSTATUS nt_status;
215
+ IO_STATUS_BLOCK io_status;
216
+ FILE_MODE_INFORMATION mode_info;
217
+ DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
218
+
219
+ if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
220
+ /* If this returns ERROR_INVALID_PARAMETER we probably opened something */
221
+ /* that is not a pipe. */
222
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
223
+ SetLastError(WSAENOTSOCK);
224
+ }
225
+ return -1;
226
+ }
227
+
228
+ /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
229
+ nt_status = pNtQueryInformationFile(pipeHandle,
230
+ &io_status,
231
+ &mode_info,
232
+ sizeof(mode_info),
233
+ FileModeInformation);
234
+ if (nt_status != STATUS_SUCCESS) {
235
+ return -1;
236
+ }
237
+
238
+ if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
239
+ mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
240
+ /* Non-overlapped pipe. */
241
+ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
242
+ } else {
243
+ /* Overlapped pipe. Try to associate with IOCP. */
244
+ if (CreateIoCompletionPort(pipeHandle,
245
+ loop->iocp,
246
+ (ULONG_PTR)handle,
247
+ 0) == NULL) {
248
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
249
+ }
250
+ }
251
+
252
+ handle->handle = pipeHandle;
253
+ handle->flags |= duplex_flags;
254
+
255
+ return 0;
256
+ }
257
+
258
+
259
+ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
260
+ uv_loop_t* loop;
261
+ uv_pipe_t* handle;
262
+ uv_shutdown_t* req;
263
+
264
+ req = (uv_shutdown_t*) parameter;
265
+ assert(req);
266
+ handle = (uv_pipe_t*) req->handle;
267
+ assert(handle);
268
+ loop = handle->loop;
269
+ assert(loop);
270
+
271
+ FlushFileBuffers(handle->handle);
272
+
273
+ /* Post completed */
274
+ POST_COMPLETION_FOR_REQ(loop, req);
275
+
276
+ return 0;
277
+ }
278
+
279
+
280
+ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
281
+ DWORD result;
282
+ uv_shutdown_t* req;
283
+ NTSTATUS nt_status;
284
+ IO_STATUS_BLOCK io_status;
285
+ FILE_PIPE_LOCAL_INFORMATION pipe_info;
286
+
287
+ if ((handle->flags & UV_HANDLE_CONNECTION) &&
288
+ handle->shutdown_req != NULL &&
289
+ handle->write_reqs_pending == 0) {
290
+ req = handle->shutdown_req;
291
+
292
+ /* Clear the shutdown_req field so we don't go here again. */
293
+ handle->shutdown_req = NULL;
294
+
295
+ if (handle->flags & UV_HANDLE_CLOSING) {
296
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
297
+
298
+ /* Already closing. Cancel the shutdown. */
299
+ if (req->cb) {
300
+ uv__set_artificial_error(loop, UV_ECANCELED);
301
+ req->cb(req, -1);
302
+ }
303
+
304
+ DECREASE_PENDING_REQ_COUNT(handle);
305
+ return;
306
+ }
307
+
308
+ /* Try to avoid flushing the pipe buffer in the thread pool. */
309
+ nt_status = pNtQueryInformationFile(handle->handle,
310
+ &io_status,
311
+ &pipe_info,
312
+ sizeof pipe_info,
313
+ FilePipeLocalInformation);
314
+
315
+ if (nt_status != STATUS_SUCCESS) {
316
+ /* Failure */
317
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
318
+
319
+ handle->flags &= ~UV_HANDLE_SHUTTING;
320
+ if (req->cb) {
321
+ uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status));
322
+ req->cb(req, -1);
323
+ }
324
+
325
+ DECREASE_PENDING_REQ_COUNT(handle);
326
+ return;
327
+ }
328
+
329
+ if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
330
+ /* Short-circuit, no need to call FlushFileBuffers. */
331
+ uv_insert_pending_req(loop, (uv_req_t*) req);
332
+ return;
333
+ }
334
+
335
+ /* Run FlushFileBuffers in the thread pool. */
336
+ result = QueueUserWorkItem(pipe_shutdown_thread_proc,
337
+ req,
338
+ WT_EXECUTELONGFUNCTION);
339
+ if (result) {
340
+ return;
341
+
342
+ } else {
343
+ /* Failure. */
344
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
345
+
346
+ handle->flags &= ~UV_HANDLE_SHUTTING;
347
+ if (req->cb) {
348
+ uv__set_sys_error(loop, GetLastError());
349
+ req->cb(req, -1);
350
+ }
351
+
352
+ DECREASE_PENDING_REQ_COUNT(handle);
353
+ return;
354
+ }
355
+ }
356
+
357
+ if (handle->flags & UV_HANDLE_CLOSING &&
358
+ handle->reqs_pending == 0) {
359
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
360
+ uv__handle_stop(handle);
361
+
362
+ if (handle->flags & UV_HANDLE_CONNECTION) {
363
+ if (handle->pending_ipc_info.socket_info) {
364
+ free(handle->pending_ipc_info.socket_info);
365
+ handle->pending_ipc_info.socket_info = NULL;
366
+ }
367
+
368
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
369
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
370
+ UnregisterWait(handle->read_req.wait_handle);
371
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
372
+ }
373
+ if (handle->read_req.event_handle) {
374
+ CloseHandle(handle->read_req.event_handle);
375
+ handle->read_req.event_handle = NULL;
376
+ }
377
+ }
378
+ }
379
+
380
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
381
+ assert(handle->accept_reqs);
382
+ free(handle->accept_reqs);
383
+ handle->accept_reqs = NULL;
384
+ }
385
+
386
+ uv__handle_close(handle);
387
+ }
388
+ }
389
+
390
+
391
+ void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
392
+ handle->pending_instances = count;
393
+ handle->flags |= UV_HANDLE_PIPESERVER;
394
+ }
395
+
396
+
397
+ /* Creates a pipe server. */
398
+ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
399
+ uv_loop_t* loop = handle->loop;
400
+ int i, errorno, nameSize;
401
+ uv_pipe_accept_t* req;
402
+
403
+ if (handle->flags & UV_HANDLE_BOUND) {
404
+ uv__set_sys_error(loop, WSAEINVAL);
405
+ return -1;
406
+ }
407
+
408
+ if (!name) {
409
+ uv__set_sys_error(loop, WSAEINVAL);
410
+ return -1;
411
+ }
412
+
413
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
414
+ handle->pending_instances = default_pending_pipe_instances;
415
+ }
416
+
417
+ handle->accept_reqs = (uv_pipe_accept_t*)
418
+ malloc(sizeof(uv_pipe_accept_t) * handle->pending_instances);
419
+ if (!handle->accept_reqs) {
420
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
421
+ }
422
+
423
+ for (i = 0; i < handle->pending_instances; i++) {
424
+ req = &handle->accept_reqs[i];
425
+ uv_req_init(loop, (uv_req_t*) req);
426
+ req->type = UV_ACCEPT;
427
+ req->data = handle;
428
+ req->pipeHandle = INVALID_HANDLE_VALUE;
429
+ req->next_pending = NULL;
430
+ }
431
+
432
+ /* Convert name to UTF16. */
433
+ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
434
+ handle->name = (WCHAR*)malloc(nameSize);
435
+ if (!handle->name) {
436
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
437
+ }
438
+
439
+ if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
440
+ uv__set_sys_error(loop, GetLastError());
441
+ return -1;
442
+ }
443
+
444
+ /*
445
+ * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
446
+ * If this fails then there's already a pipe server for the given pipe name.
447
+ */
448
+ handle->accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
449
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
450
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
451
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
452
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
453
+
454
+ if (handle->accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
455
+ errorno = GetLastError();
456
+ if (errorno == ERROR_ACCESS_DENIED) {
457
+ uv__set_error(loop, UV_EADDRINUSE, errorno);
458
+ } else if (errorno == ERROR_PATH_NOT_FOUND || errorno == ERROR_INVALID_NAME) {
459
+ uv__set_error(loop, UV_EACCES, errorno);
460
+ } else {
461
+ uv__set_sys_error(loop, errorno);
462
+ }
463
+ goto error;
464
+ }
465
+
466
+ if (uv_set_pipe_handle(loop, handle, handle->accept_reqs[0].pipeHandle, 0)) {
467
+ uv__set_sys_error(loop, GetLastError());
468
+ goto error;
469
+ }
470
+
471
+ handle->pending_accepts = NULL;
472
+ handle->flags |= UV_HANDLE_PIPESERVER;
473
+ handle->flags |= UV_HANDLE_BOUND;
474
+
475
+ return 0;
476
+
477
+ error:
478
+ if (handle->name) {
479
+ free(handle->name);
480
+ handle->name = NULL;
481
+ }
482
+
483
+ if (handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
484
+ CloseHandle(handle->accept_reqs[0].pipeHandle);
485
+ handle->accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
486
+ }
487
+
488
+ return -1;
489
+ }
490
+
491
+
492
+ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
493
+ uv_loop_t* loop;
494
+ uv_pipe_t* handle;
495
+ uv_connect_t* req;
496
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
497
+ DWORD duplex_flags;
498
+
499
+ req = (uv_connect_t*) parameter;
500
+ assert(req);
501
+ handle = (uv_pipe_t*) req->handle;
502
+ assert(handle);
503
+ loop = handle->loop;
504
+ assert(loop);
505
+
506
+ /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
507
+ /* We wait for the pipe to become available with WaitNamedPipe. */
508
+ while (WaitNamedPipeW(handle->name, 30000)) {
509
+ /* The pipe is now available, try to connect. */
510
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
511
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
512
+ break;
513
+ }
514
+
515
+ SwitchToThread();
516
+ }
517
+
518
+ if (pipeHandle != INVALID_HANDLE_VALUE &&
519
+ !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) {
520
+ SET_REQ_SUCCESS(req);
521
+ } else {
522
+ SET_REQ_ERROR(req, GetLastError());
523
+ }
524
+
525
+ /* Post completed */
526
+ POST_COMPLETION_FOR_REQ(loop, req);
527
+
528
+ return 0;
529
+ }
530
+
531
+
532
+ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
533
+ const char* name, uv_connect_cb cb) {
534
+ uv_loop_t* loop = handle->loop;
535
+ int errorno, nameSize;
536
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
537
+ DWORD duplex_flags;
538
+
539
+ uv_req_init(loop, (uv_req_t*) req);
540
+ req->type = UV_CONNECT;
541
+ req->handle = (uv_stream_t*) handle;
542
+ req->cb = cb;
543
+
544
+ /* Convert name to UTF16. */
545
+ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
546
+ handle->name = (WCHAR*)malloc(nameSize);
547
+ if (!handle->name) {
548
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
549
+ }
550
+
551
+ if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
552
+ errorno = GetLastError();
553
+ goto error;
554
+ }
555
+
556
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
557
+ if (pipeHandle == INVALID_HANDLE_VALUE) {
558
+ if (GetLastError() == ERROR_PIPE_BUSY) {
559
+ /* Wait for the server to make a pipe instance available. */
560
+ if (!QueueUserWorkItem(&pipe_connect_thread_proc,
561
+ req,
562
+ WT_EXECUTELONGFUNCTION)) {
563
+ errorno = GetLastError();
564
+ goto error;
565
+ }
566
+
567
+ REGISTER_HANDLE_REQ(loop, handle, req);
568
+ handle->reqs_pending++;
569
+
570
+ return;
571
+ }
572
+
573
+ errorno = GetLastError();
574
+ goto error;
575
+ }
576
+
577
+ assert(pipeHandle != INVALID_HANDLE_VALUE);
578
+
579
+ if (uv_set_pipe_handle(loop,
580
+ (uv_pipe_t*) req->handle,
581
+ pipeHandle,
582
+ duplex_flags)) {
583
+ errorno = GetLastError();
584
+ goto error;
585
+ }
586
+
587
+ SET_REQ_SUCCESS(req);
588
+ uv_insert_pending_req(loop, (uv_req_t*) req);
589
+ handle->reqs_pending++;
590
+ REGISTER_HANDLE_REQ(loop, handle, req);
591
+ return;
592
+
593
+ error:
594
+ if (handle->name) {
595
+ free(handle->name);
596
+ handle->name = NULL;
597
+ }
598
+
599
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
600
+ CloseHandle(pipeHandle);
601
+ }
602
+
603
+ /* Make this req pending reporting an error. */
604
+ SET_REQ_ERROR(req, errorno);
605
+ uv_insert_pending_req(loop, (uv_req_t*) req);
606
+ handle->reqs_pending++;
607
+ REGISTER_HANDLE_REQ(loop, handle, req);
608
+ return;
609
+ }
610
+
611
+
612
+ /* Cleans up uv_pipe_t (server or connection) and all resources associated */
613
+ /* with it. */
614
+ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
615
+ int i;
616
+ HANDLE pipeHandle;
617
+
618
+ if (handle->name) {
619
+ free(handle->name);
620
+ handle->name = NULL;
621
+ }
622
+
623
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
624
+ for (i = 0; i < handle->pending_instances; i++) {
625
+ pipeHandle = handle->accept_reqs[i].pipeHandle;
626
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
627
+ CloseHandle(pipeHandle);
628
+ handle->accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
629
+ }
630
+ }
631
+ }
632
+
633
+ if (handle->flags & UV_HANDLE_CONNECTION) {
634
+ handle->flags |= UV_HANDLE_SHUTTING;
635
+ eof_timer_destroy(handle);
636
+ }
637
+
638
+ if ((handle->flags & UV_HANDLE_CONNECTION)
639
+ && handle->handle != INVALID_HANDLE_VALUE) {
640
+ CloseHandle(handle->handle);
641
+ handle->handle = INVALID_HANDLE_VALUE;
642
+ }
643
+ }
644
+
645
+
646
+ void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
647
+ if (handle->flags & UV_HANDLE_READING) {
648
+ handle->flags &= ~UV_HANDLE_READING;
649
+ DECREASE_ACTIVE_COUNT(loop, handle);
650
+ }
651
+
652
+ if (handle->flags & UV_HANDLE_LISTENING) {
653
+ handle->flags &= ~UV_HANDLE_LISTENING;
654
+ DECREASE_ACTIVE_COUNT(loop, handle);
655
+ }
656
+
657
+ uv_pipe_cleanup(loop, handle);
658
+
659
+ if (handle->reqs_pending == 0) {
660
+ uv_want_endgame(loop, (uv_handle_t*) handle);
661
+ }
662
+
663
+ uv__handle_start(handle);
664
+ }
665
+
666
+
667
+ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
668
+ uv_pipe_accept_t* req, BOOL firstInstance) {
669
+ assert(handle->flags & UV_HANDLE_LISTENING);
670
+
671
+ if (!firstInstance) {
672
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
673
+
674
+ req->pipeHandle = CreateNamedPipeW(handle->name,
675
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
676
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
677
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
678
+
679
+ if (req->pipeHandle == INVALID_HANDLE_VALUE) {
680
+ SET_REQ_ERROR(req, GetLastError());
681
+ uv_insert_pending_req(loop, (uv_req_t*) req);
682
+ handle->reqs_pending++;
683
+ return;
684
+ }
685
+
686
+ if (uv_set_pipe_handle(loop, handle, req->pipeHandle, 0)) {
687
+ CloseHandle(req->pipeHandle);
688
+ req->pipeHandle = INVALID_HANDLE_VALUE;
689
+ SET_REQ_ERROR(req, GetLastError());
690
+ uv_insert_pending_req(loop, (uv_req_t*) req);
691
+ handle->reqs_pending++;
692
+ return;
693
+ }
694
+ }
695
+
696
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
697
+
698
+ /* Prepare the overlapped structure. */
699
+ memset(&(req->overlapped), 0, sizeof(req->overlapped));
700
+
701
+ if (!ConnectNamedPipe(req->pipeHandle, &req->overlapped) &&
702
+ GetLastError() != ERROR_IO_PENDING) {
703
+ if (GetLastError() == ERROR_PIPE_CONNECTED) {
704
+ SET_REQ_SUCCESS(req);
705
+ } else {
706
+ CloseHandle(req->pipeHandle);
707
+ req->pipeHandle = INVALID_HANDLE_VALUE;
708
+ /* Make this req pending reporting an error. */
709
+ SET_REQ_ERROR(req, GetLastError());
710
+ }
711
+ uv_insert_pending_req(loop, (uv_req_t*) req);
712
+ handle->reqs_pending++;
713
+ return;
714
+ }
715
+
716
+ handle->reqs_pending++;
717
+ }
718
+
719
+
720
+ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
721
+ uv_loop_t* loop = server->loop;
722
+ uv_pipe_t* pipe_client;
723
+ uv_pipe_accept_t* req;
724
+
725
+ if (server->ipc) {
726
+ if (!server->pending_ipc_info.socket_info) {
727
+ /* No valid pending sockets. */
728
+ uv__set_sys_error(loop, WSAEWOULDBLOCK);
729
+ return -1;
730
+ }
731
+
732
+ return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info,
733
+ server->pending_ipc_info.tcp_connection);
734
+ } else {
735
+ pipe_client = (uv_pipe_t*)client;
736
+
737
+ /* Find a connection instance that has been connected, but not yet */
738
+ /* accepted. */
739
+ req = server->pending_accepts;
740
+
741
+ if (!req) {
742
+ /* No valid connections found, so we error out. */
743
+ uv__set_sys_error(loop, WSAEWOULDBLOCK);
744
+ return -1;
745
+ }
746
+
747
+ /* Initialize the client handle and copy the pipeHandle to the client */
748
+ uv_pipe_connection_init(pipe_client);
749
+ pipe_client->handle = req->pipeHandle;
750
+
751
+ /* Prepare the req to pick up a new connection */
752
+ server->pending_accepts = req->next_pending;
753
+ req->next_pending = NULL;
754
+ req->pipeHandle = INVALID_HANDLE_VALUE;
755
+
756
+ if (!(server->flags & UV_HANDLE_CLOSING)) {
757
+ uv_pipe_queue_accept(loop, server, req, FALSE);
758
+ }
759
+ }
760
+
761
+ return 0;
762
+ }
763
+
764
+
765
+ /* Starts listening for connections for the given pipe. */
766
+ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
767
+ uv_loop_t* loop = handle->loop;
768
+ int i;
769
+
770
+ if (handle->flags & UV_HANDLE_LISTENING) {
771
+ handle->connection_cb = cb;
772
+ }
773
+
774
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
775
+ uv__set_artificial_error(loop, UV_EINVAL);
776
+ return -1;
777
+ }
778
+
779
+ if (handle->flags & UV_HANDLE_READING) {
780
+ uv__set_artificial_error(loop, UV_EISCONN);
781
+ return -1;
782
+ }
783
+
784
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
785
+ uv__set_artificial_error(loop, UV_ENOTSUP);
786
+ return -1;
787
+ }
788
+
789
+ handle->flags |= UV_HANDLE_LISTENING;
790
+ INCREASE_ACTIVE_COUNT(loop, handle);
791
+ handle->connection_cb = cb;
792
+
793
+ /* First pipe handle should have already been created in uv_pipe_bind */
794
+ assert(handle->accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
795
+
796
+ for (i = 0; i < handle->pending_instances; i++) {
797
+ uv_pipe_queue_accept(loop, handle, &handle->accept_reqs[i], i == 0);
798
+ }
799
+
800
+ return 0;
801
+ }
802
+
803
+
804
+ static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
805
+ int result;
806
+ DWORD bytes;
807
+ uv_read_t* req = (uv_read_t*) parameter;
808
+ uv_pipe_t* handle = (uv_pipe_t*) req->data;
809
+ uv_loop_t* loop = handle->loop;
810
+
811
+ assert(req != NULL);
812
+ assert(req->type == UV_READ);
813
+ assert(handle->type == UV_NAMED_PIPE);
814
+
815
+ result = ReadFile(handle->handle,
816
+ &uv_zero_,
817
+ 0,
818
+ &bytes,
819
+ NULL);
820
+
821
+ if (!result) {
822
+ SET_REQ_ERROR(req, GetLastError());
823
+ }
824
+
825
+ POST_COMPLETION_FOR_REQ(loop, req);
826
+ return 0;
827
+ }
828
+
829
+
830
+ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
831
+ int result;
832
+ DWORD bytes;
833
+ uv_write_t* req = (uv_write_t*) parameter;
834
+ uv_pipe_t* handle = (uv_pipe_t*) req->handle;
835
+ uv_loop_t* loop = handle->loop;
836
+
837
+ assert(req != NULL);
838
+ assert(req->type == UV_WRITE);
839
+ assert(handle->type == UV_NAMED_PIPE);
840
+ assert(req->write_buffer.base);
841
+
842
+ result = WriteFile(handle->handle,
843
+ req->write_buffer.base,
844
+ req->write_buffer.len,
845
+ &bytes,
846
+ NULL);
847
+
848
+ if (!result) {
849
+ SET_REQ_ERROR(req, GetLastError());
850
+ }
851
+
852
+ POST_COMPLETION_FOR_REQ(loop, req);
853
+ return 0;
854
+ }
855
+
856
+
857
+ static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
858
+ uv_read_t* req;
859
+ uv_tcp_t* handle;
860
+
861
+ req = (uv_read_t*) context;
862
+ assert(req != NULL);
863
+ handle = (uv_tcp_t*)req->data;
864
+ assert(handle != NULL);
865
+ assert(!timed_out);
866
+
867
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
868
+ req->overlapped.InternalHigh,
869
+ 0,
870
+ &req->overlapped)) {
871
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
872
+ }
873
+ }
874
+
875
+
876
+ static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
877
+ uv_write_t* req;
878
+ uv_tcp_t* handle;
879
+
880
+ req = (uv_write_t*) context;
881
+ assert(req != NULL);
882
+ handle = (uv_tcp_t*)req->handle;
883
+ assert(handle != NULL);
884
+ assert(!timed_out);
885
+
886
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
887
+ req->overlapped.InternalHigh,
888
+ 0,
889
+ &req->overlapped)) {
890
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
891
+ }
892
+ }
893
+
894
+
895
+ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
896
+ uv_read_t* req;
897
+ int result;
898
+
899
+ assert(handle->flags & UV_HANDLE_READING);
900
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
901
+
902
+ assert(handle->handle != INVALID_HANDLE_VALUE);
903
+
904
+ req = &handle->read_req;
905
+
906
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
907
+ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
908
+ req,
909
+ WT_EXECUTELONGFUNCTION)) {
910
+ /* Make this req pending reporting an error. */
911
+ SET_REQ_ERROR(req, GetLastError());
912
+ goto error;
913
+ }
914
+ } else {
915
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
916
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
917
+ req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1);
918
+ }
919
+
920
+ /* Do 0-read */
921
+ result = ReadFile(handle->handle,
922
+ &uv_zero_,
923
+ 0,
924
+ NULL,
925
+ &req->overlapped);
926
+
927
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
928
+ /* Make this req pending reporting an error. */
929
+ SET_REQ_ERROR(req, GetLastError());
930
+ goto error;
931
+ }
932
+
933
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
934
+ if (!req->event_handle) {
935
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
936
+ if (!req->event_handle) {
937
+ uv_fatal_error(GetLastError(), "CreateEvent");
938
+ }
939
+ }
940
+ if (req->wait_handle == INVALID_HANDLE_VALUE) {
941
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
942
+ req->overlapped.hEvent, post_completion_read_wait, (void*) req,
943
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
944
+ SET_REQ_ERROR(req, GetLastError());
945
+ goto error;
946
+ }
947
+ }
948
+ }
949
+ }
950
+
951
+ /* Start the eof timer if there is one */
952
+ eof_timer_start(handle);
953
+ handle->flags |= UV_HANDLE_READ_PENDING;
954
+ handle->reqs_pending++;
955
+ return;
956
+
957
+ error:
958
+ uv_insert_pending_req(loop, (uv_req_t*)req);
959
+ handle->flags |= UV_HANDLE_READ_PENDING;
960
+ handle->reqs_pending++;
961
+ }
962
+
963
+
964
+ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
965
+ uv_read_cb read_cb, uv_read2_cb read2_cb) {
966
+ uv_loop_t* loop = handle->loop;
967
+
968
+ if (!(handle->flags & UV_HANDLE_CONNECTION)) {
969
+ uv__set_artificial_error(loop, UV_EINVAL);
970
+ return -1;
971
+ }
972
+
973
+ if (handle->flags & UV_HANDLE_EOF) {
974
+ uv__set_artificial_error(loop, UV_EOF);
975
+ return -1;
976
+ }
977
+
978
+ handle->flags |= UV_HANDLE_READING;
979
+ INCREASE_ACTIVE_COUNT(loop, handle);
980
+ handle->read_cb = read_cb;
981
+ handle->read2_cb = read2_cb;
982
+ handle->alloc_cb = alloc_cb;
983
+
984
+ /* If reading was stopped and then started again, there could still be a */
985
+ /* read request pending. */
986
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
987
+ uv_pipe_queue_read(loop, handle);
988
+
989
+ return 0;
990
+ }
991
+
992
+
993
+ int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
994
+ uv_read_cb read_cb) {
995
+ return uv_pipe_read_start_impl(handle, alloc_cb, read_cb, NULL);
996
+ }
997
+
998
+
999
+ int uv_pipe_read2_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
1000
+ uv_read2_cb read_cb) {
1001
+ return uv_pipe_read_start_impl(handle, alloc_cb, NULL, read_cb);
1002
+ }
1003
+
1004
+
1005
+ static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
1006
+ uv_write_t* req) {
1007
+ req->next_req = NULL;
1008
+ if (handle->non_overlapped_writes_tail) {
1009
+ req->next_req =
1010
+ handle->non_overlapped_writes_tail->next_req;
1011
+ handle->non_overlapped_writes_tail->next_req = (uv_req_t*)req;
1012
+ handle->non_overlapped_writes_tail = req;
1013
+ } else {
1014
+ req->next_req = (uv_req_t*)req;
1015
+ handle->non_overlapped_writes_tail = req;
1016
+ }
1017
+ }
1018
+
1019
+
1020
+ static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
1021
+ uv_write_t* req;
1022
+
1023
+ if (handle->non_overlapped_writes_tail) {
1024
+ req = (uv_write_t*)handle->non_overlapped_writes_tail->next_req;
1025
+
1026
+ if (req == handle->non_overlapped_writes_tail) {
1027
+ handle->non_overlapped_writes_tail = NULL;
1028
+ } else {
1029
+ handle->non_overlapped_writes_tail->next_req =
1030
+ req->next_req;
1031
+ }
1032
+
1033
+ return req;
1034
+ } else {
1035
+ /* queue empty */
1036
+ return NULL;
1037
+ }
1038
+ }
1039
+
1040
+
1041
+ static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
1042
+ uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
1043
+ if (req) {
1044
+ if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
1045
+ req,
1046
+ WT_EXECUTELONGFUNCTION)) {
1047
+ uv_fatal_error(GetLastError(), "QueueUserWorkItem");
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+
1053
+ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
1054
+ uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt,
1055
+ uv_stream_t* send_handle, uv_write_cb cb) {
1056
+ int result;
1057
+ uv_tcp_t* tcp_send_handle;
1058
+ uv_write_t* ipc_header_req;
1059
+ uv_ipc_frame_uv_stream ipc_frame;
1060
+
1061
+ if (bufcnt != 1 && (bufcnt != 0 || !send_handle)) {
1062
+ uv__set_artificial_error(loop, UV_ENOTSUP);
1063
+ return -1;
1064
+ }
1065
+
1066
+ /* Only TCP handles are supported for sharing. */
1067
+ if (send_handle && ((send_handle->type != UV_TCP) ||
1068
+ (!(send_handle->flags & UV_HANDLE_BOUND) &&
1069
+ !(send_handle->flags & UV_HANDLE_CONNECTION)))) {
1070
+ uv__set_artificial_error(loop, UV_ENOTSUP);
1071
+ return -1;
1072
+ }
1073
+
1074
+ assert(handle->handle != INVALID_HANDLE_VALUE);
1075
+
1076
+ if (!(handle->flags & UV_HANDLE_CONNECTION)) {
1077
+ uv__set_artificial_error(loop, UV_EINVAL);
1078
+ return -1;
1079
+ }
1080
+
1081
+ if (handle->flags & UV_HANDLE_SHUTTING) {
1082
+ uv__set_artificial_error(loop, UV_EOF);
1083
+ return -1;
1084
+ }
1085
+
1086
+ uv_req_init(loop, (uv_req_t*) req);
1087
+ req->type = UV_WRITE;
1088
+ req->handle = (uv_stream_t*) handle;
1089
+ req->cb = cb;
1090
+ req->ipc_header = 0;
1091
+ req->event_handle = NULL;
1092
+ req->wait_handle = INVALID_HANDLE_VALUE;
1093
+ memset(&req->overlapped, 0, sizeof(req->overlapped));
1094
+
1095
+ if (handle->ipc) {
1096
+ assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
1097
+ ipc_frame.header.flags = 0;
1098
+
1099
+ /* Use the IPC framing protocol. */
1100
+ if (send_handle) {
1101
+ tcp_send_handle = (uv_tcp_t*)send_handle;
1102
+
1103
+ if (uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
1104
+ &ipc_frame.socket_info)) {
1105
+ return -1;
1106
+ }
1107
+ ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
1108
+
1109
+ if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
1110
+ ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION;
1111
+ }
1112
+ }
1113
+
1114
+ if (bufcnt == 1) {
1115
+ ipc_frame.header.flags |= UV_IPC_RAW_DATA;
1116
+ ipc_frame.header.raw_data_length = bufs[0].len;
1117
+ }
1118
+
1119
+ /*
1120
+ * Use the provided req if we're only doing a single write.
1121
+ * If we're doing multiple writes, use ipc_header_write_req to do
1122
+ * the first write, and then use the provided req for the second write.
1123
+ */
1124
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
1125
+ ipc_header_req = req;
1126
+ } else {
1127
+ /*
1128
+ * Try to use the preallocated write req if it's available.
1129
+ * Otherwise allocate a new one.
1130
+ */
1131
+ if (handle->ipc_header_write_req.type != UV_WRITE) {
1132
+ ipc_header_req = (uv_write_t*)&handle->ipc_header_write_req;
1133
+ } else {
1134
+ ipc_header_req = (uv_write_t*)malloc(sizeof(uv_write_t));
1135
+ if (!ipc_header_req) {
1136
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
1137
+ }
1138
+ }
1139
+
1140
+ uv_req_init(loop, (uv_req_t*) ipc_header_req);
1141
+ ipc_header_req->type = UV_WRITE;
1142
+ ipc_header_req->handle = (uv_stream_t*) handle;
1143
+ ipc_header_req->cb = NULL;
1144
+ ipc_header_req->ipc_header = 1;
1145
+ }
1146
+
1147
+ /* Write the header or the whole frame. */
1148
+ memset(&ipc_header_req->overlapped, 0, sizeof(ipc_header_req->overlapped));
1149
+
1150
+ result = WriteFile(handle->handle,
1151
+ &ipc_frame,
1152
+ ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
1153
+ sizeof(ipc_frame) : sizeof(ipc_frame.header),
1154
+ NULL,
1155
+ &ipc_header_req->overlapped);
1156
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
1157
+ uv__set_sys_error(loop, GetLastError());
1158
+ return -1;
1159
+ }
1160
+
1161
+ if (result) {
1162
+ /* Request completed immediately. */
1163
+ ipc_header_req->queued_bytes = 0;
1164
+ } else {
1165
+ /* Request queued by the kernel. */
1166
+ ipc_header_req->queued_bytes = ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
1167
+ sizeof(ipc_frame) : sizeof(ipc_frame.header);
1168
+ handle->write_queue_size += ipc_header_req->queued_bytes;
1169
+ }
1170
+
1171
+ REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
1172
+ handle->reqs_pending++;
1173
+ handle->write_reqs_pending++;
1174
+
1175
+ /* If we don't have any raw data to write - we're done. */
1176
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
1177
+ return 0;
1178
+ }
1179
+ }
1180
+
1181
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
1182
+ req->write_buffer = bufs[0];
1183
+ uv_insert_non_overlapped_write_req(handle, req);
1184
+ if (handle->write_reqs_pending == 0) {
1185
+ uv_queue_non_overlapped_write(handle);
1186
+ }
1187
+
1188
+ /* Request queued by the kernel. */
1189
+ req->queued_bytes = uv_count_bufs(bufs, bufcnt);
1190
+ handle->write_queue_size += req->queued_bytes;
1191
+ } else {
1192
+ result = WriteFile(handle->handle,
1193
+ bufs[0].base,
1194
+ bufs[0].len,
1195
+ NULL,
1196
+ &req->overlapped);
1197
+
1198
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
1199
+ uv__set_sys_error(loop, GetLastError());
1200
+ return -1;
1201
+ }
1202
+
1203
+ if (result) {
1204
+ /* Request completed immediately. */
1205
+ req->queued_bytes = 0;
1206
+ } else {
1207
+ /* Request queued by the kernel. */
1208
+ req->queued_bytes = uv_count_bufs(bufs, bufcnt);
1209
+ handle->write_queue_size += req->queued_bytes;
1210
+ }
1211
+
1212
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
1213
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
1214
+ if (!req->event_handle) {
1215
+ uv_fatal_error(GetLastError(), "CreateEvent");
1216
+ }
1217
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
1218
+ req->overlapped.hEvent, post_completion_write_wait, (void*) req,
1219
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
1220
+ uv__set_sys_error(loop, GetLastError());
1221
+ return -1;
1222
+ }
1223
+ }
1224
+ }
1225
+
1226
+ REGISTER_HANDLE_REQ(loop, handle, req);
1227
+ handle->reqs_pending++;
1228
+ handle->write_reqs_pending++;
1229
+
1230
+ return 0;
1231
+ }
1232
+
1233
+
1234
+ int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
1235
+ uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
1236
+ return uv_pipe_write_impl(loop, req, handle, bufs, bufcnt, NULL, cb);
1237
+ }
1238
+
1239
+
1240
+ int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
1241
+ uv_buf_t bufs[], int bufcnt, uv_stream_t* send_handle, uv_write_cb cb) {
1242
+ if (!handle->ipc) {
1243
+ uv__set_artificial_error(loop, UV_EINVAL);
1244
+ return -1;
1245
+ }
1246
+
1247
+ return uv_pipe_write_impl(loop, req, handle, bufs, bufcnt, send_handle, cb);
1248
+ }
1249
+
1250
+
1251
+ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
1252
+ uv_buf_t buf) {
1253
+ /* If there is an eof timer running, we don't need it any more, */
1254
+ /* so discard it. */
1255
+ eof_timer_destroy(handle);
1256
+
1257
+ handle->flags |= UV_HANDLE_EOF;
1258
+ uv_read_stop((uv_stream_t*) handle);
1259
+
1260
+ uv__set_artificial_error(loop, UV_EOF);
1261
+ if (handle->read2_cb) {
1262
+ handle->read2_cb(handle, -1, uv_null_buf_, UV_UNKNOWN_HANDLE);
1263
+ } else {
1264
+ handle->read_cb((uv_stream_t*) handle, -1, uv_null_buf_);
1265
+ }
1266
+ }
1267
+
1268
+
1269
+ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
1270
+ uv_buf_t buf) {
1271
+ /* If there is an eof timer running, we don't need it any more, */
1272
+ /* so discard it. */
1273
+ eof_timer_destroy(handle);
1274
+
1275
+ uv_read_stop((uv_stream_t*) handle);
1276
+
1277
+ uv__set_sys_error(loop, error);
1278
+ if (handle->read2_cb) {
1279
+ handle->read2_cb(handle, -1, buf, UV_UNKNOWN_HANDLE);
1280
+ } else {
1281
+ handle->read_cb((uv_stream_t*)handle, -1, buf);
1282
+ }
1283
+ }
1284
+
1285
+
1286
+ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
1287
+ int error, uv_buf_t buf) {
1288
+ if (error == ERROR_BROKEN_PIPE) {
1289
+ uv_pipe_read_eof(loop, handle, buf);
1290
+ } else {
1291
+ uv_pipe_read_error(loop, handle, error, buf);
1292
+ }
1293
+ }
1294
+
1295
+
1296
+ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
1297
+ uv_req_t* req) {
1298
+ DWORD bytes, avail;
1299
+ uv_buf_t buf;
1300
+ uv_ipc_frame_uv_stream ipc_frame;
1301
+
1302
+ assert(handle->type == UV_NAMED_PIPE);
1303
+
1304
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
1305
+ eof_timer_stop(handle);
1306
+
1307
+ if (!REQ_SUCCESS(req)) {
1308
+ /* An error occurred doing the 0-read. */
1309
+ if (handle->flags & UV_HANDLE_READING) {
1310
+ uv_pipe_read_error_or_eof(loop,
1311
+ handle,
1312
+ GET_REQ_ERROR(req),
1313
+ uv_null_buf_);
1314
+ }
1315
+ } else {
1316
+ /* Do non-blocking reads until the buffer is empty */
1317
+ while (handle->flags & UV_HANDLE_READING) {
1318
+ if (!PeekNamedPipe(handle->handle,
1319
+ NULL,
1320
+ 0,
1321
+ NULL,
1322
+ &avail,
1323
+ NULL)) {
1324
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
1325
+ break;
1326
+ }
1327
+
1328
+ if (avail == 0) {
1329
+ /* There is nothing to read after all. */
1330
+ break;
1331
+ }
1332
+
1333
+ if (handle->ipc) {
1334
+ /* Use the IPC framing protocol to read the incoming data. */
1335
+ if (handle->remaining_ipc_rawdata_bytes == 0) {
1336
+ /* We're reading a new frame. First, read the header. */
1337
+ assert(avail >= sizeof(ipc_frame.header));
1338
+
1339
+ if (!ReadFile(handle->handle,
1340
+ &ipc_frame.header,
1341
+ sizeof(ipc_frame.header),
1342
+ &bytes,
1343
+ NULL)) {
1344
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
1345
+ uv_null_buf_);
1346
+ break;
1347
+ }
1348
+
1349
+ assert(bytes == sizeof(ipc_frame.header));
1350
+ assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA |
1351
+ UV_IPC_TCP_CONNECTION));
1352
+
1353
+ if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
1354
+ assert(avail - sizeof(ipc_frame.header) >=
1355
+ sizeof(ipc_frame.socket_info));
1356
+
1357
+ /* Read the TCP socket info. */
1358
+ if (!ReadFile(handle->handle,
1359
+ &ipc_frame.socket_info,
1360
+ sizeof(ipc_frame) - sizeof(ipc_frame.header),
1361
+ &bytes,
1362
+ NULL)) {
1363
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
1364
+ uv_null_buf_);
1365
+ break;
1366
+ }
1367
+
1368
+ assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header));
1369
+
1370
+ /* Store the pending socket info. */
1371
+ assert(!handle->pending_ipc_info.socket_info);
1372
+ handle->pending_ipc_info.socket_info =
1373
+ (WSAPROTOCOL_INFOW*)malloc(sizeof(*(handle->pending_ipc_info.socket_info)));
1374
+ if (!handle->pending_ipc_info.socket_info) {
1375
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
1376
+ }
1377
+
1378
+ *(handle->pending_ipc_info.socket_info) = ipc_frame.socket_info;
1379
+ handle->pending_ipc_info.tcp_connection =
1380
+ ipc_frame.header.flags & UV_IPC_TCP_CONNECTION;
1381
+ }
1382
+
1383
+ if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
1384
+ handle->remaining_ipc_rawdata_bytes =
1385
+ ipc_frame.header.raw_data_length;
1386
+ continue;
1387
+ }
1388
+ } else {
1389
+ avail = min(avail, (DWORD)handle->remaining_ipc_rawdata_bytes);
1390
+ }
1391
+ }
1392
+
1393
+ buf = handle->alloc_cb((uv_handle_t*) handle, avail);
1394
+ assert(buf.len > 0);
1395
+
1396
+ if (ReadFile(handle->handle,
1397
+ buf.base,
1398
+ buf.len,
1399
+ &bytes,
1400
+ NULL)) {
1401
+ /* Successful read */
1402
+ if (handle->ipc) {
1403
+ assert(handle->remaining_ipc_rawdata_bytes >= bytes);
1404
+ handle->remaining_ipc_rawdata_bytes =
1405
+ handle->remaining_ipc_rawdata_bytes - bytes;
1406
+ if (handle->read2_cb) {
1407
+ handle->read2_cb(handle, bytes, buf,
1408
+ handle->pending_ipc_info.socket_info ? UV_TCP : UV_UNKNOWN_HANDLE);
1409
+ } else if (handle->read_cb) {
1410
+ handle->read_cb((uv_stream_t*)handle, bytes, buf);
1411
+ }
1412
+
1413
+ if (handle->pending_ipc_info.socket_info) {
1414
+ free(handle->pending_ipc_info.socket_info);
1415
+ handle->pending_ipc_info.socket_info = NULL;
1416
+ }
1417
+ } else {
1418
+ handle->read_cb((uv_stream_t*)handle, bytes, buf);
1419
+ }
1420
+
1421
+ /* Read again only if bytes == buf.len */
1422
+ if (bytes <= buf.len) {
1423
+ break;
1424
+ }
1425
+ } else {
1426
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
1427
+ break;
1428
+ }
1429
+ }
1430
+
1431
+ /* Post another 0-read if still reading and not closing. */
1432
+ if ((handle->flags & UV_HANDLE_READING) &&
1433
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
1434
+ uv_pipe_queue_read(loop, handle);
1435
+ }
1436
+ }
1437
+
1438
+ DECREASE_PENDING_REQ_COUNT(handle);
1439
+ }
1440
+
1441
+
1442
+ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
1443
+ uv_write_t* req) {
1444
+ assert(handle->type == UV_NAMED_PIPE);
1445
+
1446
+ assert(handle->write_queue_size >= req->queued_bytes);
1447
+ handle->write_queue_size -= req->queued_bytes;
1448
+
1449
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
1450
+
1451
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
1452
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
1453
+ UnregisterWait(req->wait_handle);
1454
+ req->wait_handle = INVALID_HANDLE_VALUE;
1455
+ }
1456
+ if (req->event_handle) {
1457
+ CloseHandle(req->event_handle);
1458
+ req->event_handle = NULL;
1459
+ }
1460
+ }
1461
+
1462
+ if (req->ipc_header) {
1463
+ if (req == &handle->ipc_header_write_req) {
1464
+ req->type = UV_UNKNOWN_REQ;
1465
+ } else {
1466
+ free(req);
1467
+ }
1468
+ } else {
1469
+ if (req->cb) {
1470
+ if (!REQ_SUCCESS(req)) {
1471
+ uv__set_sys_error(loop, GET_REQ_ERROR(req));
1472
+ ((uv_write_cb)req->cb)(req, -1);
1473
+ } else {
1474
+ ((uv_write_cb)req->cb)(req, 0);
1475
+ }
1476
+ }
1477
+ }
1478
+
1479
+ handle->write_reqs_pending--;
1480
+
1481
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
1482
+ handle->non_overlapped_writes_tail) {
1483
+ assert(handle->write_reqs_pending > 0);
1484
+ uv_queue_non_overlapped_write(handle);
1485
+ }
1486
+
1487
+ if (handle->write_reqs_pending == 0 &&
1488
+ handle->flags & UV_HANDLE_SHUTTING) {
1489
+ uv_want_endgame(loop, (uv_handle_t*)handle);
1490
+ }
1491
+
1492
+ DECREASE_PENDING_REQ_COUNT(handle);
1493
+ }
1494
+
1495
+
1496
+ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
1497
+ uv_req_t* raw_req) {
1498
+ uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
1499
+
1500
+ assert(handle->type == UV_NAMED_PIPE);
1501
+
1502
+ if (REQ_SUCCESS(req)) {
1503
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
1504
+ req->next_pending = handle->pending_accepts;
1505
+ handle->pending_accepts = req;
1506
+
1507
+ if (handle->connection_cb) {
1508
+ handle->connection_cb((uv_stream_t*)handle, 0);
1509
+ }
1510
+ } else {
1511
+ if (req->pipeHandle != INVALID_HANDLE_VALUE) {
1512
+ CloseHandle(req->pipeHandle);
1513
+ req->pipeHandle = INVALID_HANDLE_VALUE;
1514
+ }
1515
+ if (!(handle->flags & UV_HANDLE_CLOSING)) {
1516
+ uv_pipe_queue_accept(loop, handle, req, FALSE);
1517
+ }
1518
+ }
1519
+
1520
+ DECREASE_PENDING_REQ_COUNT(handle);
1521
+ }
1522
+
1523
+
1524
+ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
1525
+ uv_connect_t* req) {
1526
+ assert(handle->type == UV_NAMED_PIPE);
1527
+
1528
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
1529
+
1530
+ if (req->cb) {
1531
+ if (REQ_SUCCESS(req)) {
1532
+ uv_pipe_connection_init(handle);
1533
+ ((uv_connect_cb)req->cb)(req, 0);
1534
+ } else {
1535
+ uv__set_sys_error(loop, GET_REQ_ERROR(req));
1536
+ ((uv_connect_cb)req->cb)(req, -1);
1537
+ }
1538
+ }
1539
+
1540
+ DECREASE_PENDING_REQ_COUNT(handle);
1541
+ }
1542
+
1543
+
1544
+ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
1545
+ uv_shutdown_t* req) {
1546
+ assert(handle->type == UV_NAMED_PIPE);
1547
+
1548
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
1549
+
1550
+ /* Initialize and optionally start the eof timer. */
1551
+ /* This makes no sense if we've already seen EOF. */
1552
+ if (!(handle->flags & UV_HANDLE_EOF)) {
1553
+ eof_timer_init(handle);
1554
+
1555
+ /* If reading start the timer right now. */
1556
+ /* Otherwise uv_pipe_queue_read will start it. */
1557
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
1558
+ eof_timer_start(handle);
1559
+ }
1560
+ }
1561
+
1562
+ if (req->cb) {
1563
+ req->cb(req, 0);
1564
+ }
1565
+
1566
+ DECREASE_PENDING_REQ_COUNT(handle);
1567
+ }
1568
+
1569
+
1570
+ static void eof_timer_init(uv_pipe_t* pipe) {
1571
+ int r;
1572
+
1573
+ assert(pipe->eof_timer == NULL);
1574
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
1575
+
1576
+ pipe->eof_timer = (uv_timer_t*) malloc(sizeof *pipe->eof_timer);
1577
+
1578
+ r = uv_timer_init(pipe->loop, pipe->eof_timer);
1579
+ assert(r == 0); /* timers can't fail */
1580
+ pipe->eof_timer->data = pipe;
1581
+ uv_unref((uv_handle_t*) pipe->eof_timer);
1582
+ }
1583
+
1584
+
1585
+ static void eof_timer_start(uv_pipe_t* pipe) {
1586
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
1587
+
1588
+ if (pipe->eof_timer != NULL) {
1589
+ uv_timer_start(pipe->eof_timer, eof_timer_cb, eof_timeout, 0);
1590
+ }
1591
+ }
1592
+
1593
+
1594
+ static void eof_timer_stop(uv_pipe_t* pipe) {
1595
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
1596
+
1597
+ if (pipe->eof_timer != NULL) {
1598
+ uv_timer_stop(pipe->eof_timer);
1599
+ }
1600
+ }
1601
+
1602
+
1603
+ static void eof_timer_cb(uv_timer_t* timer, int status) {
1604
+ uv_pipe_t* pipe = (uv_pipe_t*) timer->data;
1605
+ uv_loop_t* loop = timer->loop;
1606
+
1607
+ assert(status == 0); /* timers can't fail */
1608
+ assert(pipe->type == UV_NAMED_PIPE);
1609
+
1610
+ /* This should always be true, since we start the timer only */
1611
+ /* in uv_pipe_queue_read after successfully calling ReadFile, */
1612
+ /* or in uv_process_pipe_shutdown_req if a read is pending, */
1613
+ /* and we always immediately stop the timer in */
1614
+ /* uv_process_pipe_read_req. */
1615
+ assert(pipe->flags & UV_HANDLE_READ_PENDING);
1616
+
1617
+ /* If there are many packets coming off the iocp then the timer callback */
1618
+ /* may be called before the read request is coming off the queue. */
1619
+ /* Therefore we check here if the read request has completed but will */
1620
+ /* be processed later. */
1621
+ if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
1622
+ HasOverlappedIoCompleted(&pipe->read_req.overlapped)) {
1623
+ return;
1624
+ }
1625
+
1626
+ /* Force both ends off the pipe. */
1627
+ CloseHandle(pipe->handle);
1628
+ pipe->handle = INVALID_HANDLE_VALUE;
1629
+
1630
+ /* Stop reading, so the pending read that is going to fail will */
1631
+ /* not be reported to the user. */
1632
+ uv_read_stop((uv_stream_t*) pipe);
1633
+
1634
+ /* Report the eof and update flags. This will get reported even if the */
1635
+ /* user stopped reading in the meantime. TODO: is that okay? */
1636
+ uv_pipe_read_eof(loop, pipe, uv_null_buf_);
1637
+ }
1638
+
1639
+
1640
+ static void eof_timer_destroy(uv_pipe_t* pipe) {
1641
+ assert(pipe->flags && UV_HANDLE_CONNECTION);
1642
+
1643
+ if (pipe->eof_timer) {
1644
+ uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb);
1645
+ pipe->eof_timer = NULL;
1646
+ }
1647
+ }
1648
+
1649
+
1650
+ static void eof_timer_close_cb(uv_handle_t* handle) {
1651
+ assert(handle->type == UV_TIMER);
1652
+ free(handle);
1653
+ }
1654
+
1655
+
1656
+ void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
1657
+ HANDLE os_handle = (HANDLE)_get_osfhandle(file);
1658
+
1659
+ if (os_handle == INVALID_HANDLE_VALUE ||
1660
+ uv_set_pipe_handle(pipe->loop, pipe, os_handle, 0) == -1) {
1661
+ return;
1662
+ }
1663
+
1664
+ uv_pipe_connection_init(pipe);
1665
+ pipe->handle = os_handle;
1666
+
1667
+ if (pipe->ipc) {
1668
+ assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
1669
+ pipe->ipc_pid = uv_parent_pid();
1670
+ assert(pipe->ipc_pid != -1);
1671
+ }
1672
+ }