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 "task.h" |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | |
28 | #ifndef _WIN32 |
29 | # include <unistd.h> |
30 | #endif |
31 | |
32 | static int shutdown_cb_called = 0; |
33 | static int shutdown_requested = 0; |
34 | static int connect_cb_called = 0; |
35 | static int write_cb_called = 0; |
36 | static int close_cb_called = 0; |
37 | |
38 | static uv_connect_t connect_req; |
39 | static uv_shutdown_t shutdown_req; |
40 | static uv_write_t write_req; |
41 | static uv_timer_t tm; |
42 | static uv_tcp_t client; |
43 | |
44 | |
45 | static void startup(void) { |
46 | #ifdef _WIN32 |
47 | struct WSAData wsa_data; |
48 | int r = WSAStartup(MAKEWORD(2, 2), &wsa_data); |
49 | ASSERT(r == 0); |
50 | #endif |
51 | } |
52 | |
53 | |
54 | static uv_os_sock_t create_tcp_socket(void) { |
55 | uv_os_sock_t sock; |
56 | |
57 | sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); |
58 | #ifdef _WIN32 |
59 | ASSERT(sock != INVALID_SOCKET); |
60 | #else |
61 | ASSERT(sock >= 0); |
62 | #endif |
63 | |
64 | #ifndef _WIN32 |
65 | { |
66 | /* Allow reuse of the port. */ |
67 | int yes = 1; |
68 | int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); |
69 | ASSERT(r == 0); |
70 | } |
71 | #endif |
72 | |
73 | return sock; |
74 | } |
75 | |
76 | |
77 | static void close_socket(uv_os_sock_t sock) { |
78 | int r; |
79 | #ifdef _WIN32 |
80 | r = closesocket(sock); |
81 | #else |
82 | r = close(sock); |
83 | #endif |
84 | ASSERT(r == 0); |
85 | } |
86 | |
87 | |
88 | static void alloc_cb(uv_handle_t* handle, |
89 | size_t suggested_size, |
90 | uv_buf_t* buf) { |
91 | static char slab[65536]; |
92 | ASSERT(suggested_size <= sizeof(slab)); |
93 | buf->base = slab; |
94 | buf->len = sizeof(slab); |
95 | } |
96 | |
97 | |
98 | static void close_cb(uv_handle_t* handle) { |
99 | ASSERT(handle != NULL); |
100 | close_cb_called++; |
101 | } |
102 | |
103 | |
104 | static void shutdown_cb(uv_shutdown_t* req, int status) { |
105 | ASSERT(req == &shutdown_req); |
106 | ASSERT(status == 0); |
107 | |
108 | /* Now we wait for the EOF */ |
109 | shutdown_cb_called++; |
110 | } |
111 | |
112 | |
113 | static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { |
114 | ASSERT(tcp != NULL); |
115 | |
116 | if (nread >= 0) { |
117 | ASSERT(nread == 4); |
118 | ASSERT(memcmp("PING" , buf->base, nread) == 0); |
119 | } |
120 | else { |
121 | ASSERT(nread == UV_EOF); |
122 | uv_close((uv_handle_t*)tcp, close_cb); |
123 | } |
124 | } |
125 | |
126 | |
127 | static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { |
128 | int i; |
129 | ASSERT(tcp != NULL); |
130 | |
131 | if (nread >= 0) { |
132 | for (i = 0; i < nread; ++i) |
133 | ASSERT(buf->base[i] == 'P'); |
134 | } else { |
135 | ASSERT(nread == UV_EOF); |
136 | printf("GOT EOF\n" ); |
137 | uv_close((uv_handle_t*)tcp, close_cb); |
138 | } |
139 | } |
140 | |
141 | |
142 | static void write_cb(uv_write_t* req, int status) { |
143 | ASSERT(req != NULL); |
144 | |
145 | if (status) { |
146 | fprintf(stderr, "uv_write error: %s\n" , uv_strerror(status)); |
147 | ASSERT(0); |
148 | } |
149 | |
150 | write_cb_called++; |
151 | } |
152 | |
153 | |
154 | static void write1_cb(uv_write_t* req, int status) { |
155 | uv_buf_t buf; |
156 | int r; |
157 | |
158 | ASSERT(req != NULL); |
159 | if (status) { |
160 | ASSERT(shutdown_cb_called); |
161 | return; |
162 | } |
163 | |
164 | if (shutdown_requested) |
165 | return; |
166 | |
167 | buf = uv_buf_init("P" , 1); |
168 | r = uv_write(&write_req, req->handle, &buf, 1, write1_cb); |
169 | ASSERT(r == 0); |
170 | |
171 | write_cb_called++; |
172 | } |
173 | |
174 | |
175 | static void timer_cb(uv_timer_t* handle) { |
176 | int r; |
177 | |
178 | /* Shutdown on drain. */ |
179 | r = uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb); |
180 | ASSERT(r == 0); |
181 | shutdown_requested++; |
182 | } |
183 | |
184 | |
185 | static void connect_cb(uv_connect_t* req, int status) { |
186 | uv_buf_t buf = uv_buf_init("PING" , 4); |
187 | uv_stream_t* stream; |
188 | int r; |
189 | |
190 | ASSERT(req == &connect_req); |
191 | ASSERT(status == 0); |
192 | |
193 | stream = req->handle; |
194 | connect_cb_called++; |
195 | |
196 | r = uv_write(&write_req, stream, &buf, 1, write_cb); |
197 | ASSERT(r == 0); |
198 | |
199 | /* Shutdown on drain. */ |
200 | r = uv_shutdown(&shutdown_req, stream, shutdown_cb); |
201 | ASSERT(r == 0); |
202 | |
203 | /* Start reading */ |
204 | r = uv_read_start(stream, alloc_cb, read_cb); |
205 | ASSERT(r == 0); |
206 | } |
207 | |
208 | |
209 | static void connect1_cb(uv_connect_t* req, int status) { |
210 | uv_buf_t buf; |
211 | uv_stream_t* stream; |
212 | int r; |
213 | |
214 | ASSERT(req == &connect_req); |
215 | ASSERT(status == 0); |
216 | |
217 | stream = req->handle; |
218 | connect_cb_called++; |
219 | |
220 | r = uv_timer_init(uv_default_loop(), &tm); |
221 | ASSERT(r == 0); |
222 | |
223 | r = uv_timer_start(&tm, timer_cb, 2000, 0); |
224 | ASSERT(r == 0); |
225 | |
226 | buf = uv_buf_init("P" , 1); |
227 | r = uv_write(&write_req, stream, &buf, 1, write1_cb); |
228 | ASSERT(r == 0); |
229 | |
230 | /* Start reading */ |
231 | r = uv_read_start(stream, alloc_cb, read1_cb); |
232 | ASSERT(r == 0); |
233 | } |
234 | |
235 | |
236 | TEST_IMPL(tcp_open) { |
237 | struct sockaddr_in addr; |
238 | uv_os_sock_t sock; |
239 | int r; |
240 | |
241 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , TEST_PORT, &addr)); |
242 | |
243 | startup(); |
244 | sock = create_tcp_socket(); |
245 | |
246 | r = uv_tcp_init(uv_default_loop(), &client); |
247 | ASSERT(r == 0); |
248 | |
249 | r = uv_tcp_open(&client, sock); |
250 | ASSERT(r == 0); |
251 | |
252 | r = uv_tcp_connect(&connect_req, |
253 | &client, |
254 | (const struct sockaddr*) &addr, |
255 | connect_cb); |
256 | ASSERT(r == 0); |
257 | |
258 | #ifndef _WIN32 |
259 | { |
260 | uv_tcp_t client2; |
261 | |
262 | r = uv_tcp_init(uv_default_loop(), &client2); |
263 | ASSERT(r == 0); |
264 | |
265 | r = uv_tcp_open(&client2, sock); |
266 | ASSERT(r == UV_EEXIST); |
267 | |
268 | uv_close((uv_handle_t*) &client2, NULL); |
269 | } |
270 | #endif /* !_WIN32 */ |
271 | |
272 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
273 | |
274 | ASSERT(shutdown_cb_called == 1); |
275 | ASSERT(connect_cb_called == 1); |
276 | ASSERT(write_cb_called == 1); |
277 | ASSERT(close_cb_called == 1); |
278 | |
279 | MAKE_VALGRIND_HAPPY(); |
280 | return 0; |
281 | } |
282 | |
283 | |
284 | TEST_IMPL(tcp_open_twice) { |
285 | uv_tcp_t client; |
286 | uv_os_sock_t sock1, sock2; |
287 | int r; |
288 | |
289 | startup(); |
290 | sock1 = create_tcp_socket(); |
291 | sock2 = create_tcp_socket(); |
292 | |
293 | r = uv_tcp_init(uv_default_loop(), &client); |
294 | ASSERT(r == 0); |
295 | |
296 | r = uv_tcp_open(&client, sock1); |
297 | ASSERT(r == 0); |
298 | |
299 | r = uv_tcp_open(&client, sock2); |
300 | ASSERT(r == UV_EBUSY); |
301 | close_socket(sock2); |
302 | |
303 | uv_close((uv_handle_t*) &client, NULL); |
304 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
305 | |
306 | MAKE_VALGRIND_HAPPY(); |
307 | return 0; |
308 | } |
309 | |
310 | |
311 | TEST_IMPL(tcp_open_bound) { |
312 | struct sockaddr_in addr; |
313 | uv_tcp_t server; |
314 | uv_os_sock_t sock; |
315 | |
316 | startup(); |
317 | sock = create_tcp_socket(); |
318 | |
319 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , TEST_PORT, &addr)); |
320 | |
321 | ASSERT(0 == uv_tcp_init(uv_default_loop(), &server)); |
322 | |
323 | ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr))); |
324 | |
325 | ASSERT(0 == uv_tcp_open(&server, sock)); |
326 | |
327 | ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL)); |
328 | |
329 | MAKE_VALGRIND_HAPPY(); |
330 | return 0; |
331 | } |
332 | |
333 | |
334 | TEST_IMPL(tcp_open_connected) { |
335 | struct sockaddr_in addr; |
336 | uv_tcp_t client; |
337 | uv_os_sock_t sock; |
338 | uv_buf_t buf = uv_buf_init("PING" , 4); |
339 | |
340 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , TEST_PORT, &addr)); |
341 | |
342 | startup(); |
343 | sock = create_tcp_socket(); |
344 | |
345 | ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr))); |
346 | |
347 | ASSERT(0 == uv_tcp_init(uv_default_loop(), &client)); |
348 | |
349 | ASSERT(0 == uv_tcp_open(&client, sock)); |
350 | |
351 | ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb)); |
352 | |
353 | ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb)); |
354 | |
355 | ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb)); |
356 | |
357 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
358 | |
359 | ASSERT(shutdown_cb_called == 1); |
360 | ASSERT(write_cb_called == 1); |
361 | ASSERT(close_cb_called == 1); |
362 | |
363 | MAKE_VALGRIND_HAPPY(); |
364 | return 0; |
365 | } |
366 | |
367 | |
368 | TEST_IMPL(tcp_write_ready) { |
369 | struct sockaddr_in addr; |
370 | uv_os_sock_t sock; |
371 | int r; |
372 | |
373 | ASSERT(0 == uv_ip4_addr("127.0.0.1" , TEST_PORT, &addr)); |
374 | |
375 | startup(); |
376 | sock = create_tcp_socket(); |
377 | |
378 | r = uv_tcp_init(uv_default_loop(), &client); |
379 | ASSERT(r == 0); |
380 | |
381 | r = uv_tcp_open(&client, sock); |
382 | ASSERT(r == 0); |
383 | |
384 | r = uv_tcp_connect(&connect_req, |
385 | &client, |
386 | (const struct sockaddr*) &addr, |
387 | connect1_cb); |
388 | ASSERT(r == 0); |
389 | |
390 | uv_run(uv_default_loop(), UV_RUN_DEFAULT); |
391 | |
392 | ASSERT(shutdown_cb_called == 1); |
393 | ASSERT(shutdown_requested == 1); |
394 | ASSERT(connect_cb_called == 1); |
395 | ASSERT(write_cb_called > 0); |
396 | ASSERT(close_cb_called == 1); |
397 | |
398 | MAKE_VALGRIND_HAPPY(); |
399 | return 0; |
400 | } |
401 | |