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
startup(void)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
create_tcp_socket(void)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
close_socket(uv_os_sock_t sock)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
alloc_cb(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)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
close_cb(uv_handle_t * handle)98 static void close_cb(uv_handle_t* handle) {
99 ASSERT_NOT_NULL(handle);
100 close_cb_called++;
101 }
102
103
shutdown_cb(uv_shutdown_t * req,int status)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
read_cb(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)113 static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
114 ASSERT_NOT_NULL(tcp);
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
read1_cb(uv_stream_t * tcp,ssize_t nread,const uv_buf_t * buf)127 static void read1_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
128 int i;
129 ASSERT_NOT_NULL(tcp);
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
write_cb(uv_write_t * req,int status)142 static void write_cb(uv_write_t* req, int status) {
143 ASSERT_NOT_NULL(req);
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
write1_cb(uv_write_t * req,int status)154 static void write1_cb(uv_write_t* req, int status) {
155 uv_buf_t buf;
156 int r;
157
158 ASSERT_NOT_NULL(req);
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
timer_cb(uv_timer_t * handle)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
connect_cb(uv_connect_t * req,int status)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
connect1_cb(uv_connect_t * req,int status)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
TEST_IMPL(tcp_open)236 TEST_IMPL(tcp_open) {
237 struct sockaddr_in addr;
238 uv_os_sock_t sock;
239 int r;
240 uv_tcp_t client2;
241
242 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
243
244 startup();
245 sock = create_tcp_socket();
246
247 r = uv_tcp_init(uv_default_loop(), &client);
248 ASSERT(r == 0);
249
250 r = uv_tcp_open(&client, sock);
251 ASSERT(r == 0);
252
253 r = uv_tcp_connect(&connect_req,
254 &client,
255 (const struct sockaddr*) &addr,
256 connect_cb);
257 ASSERT(r == 0);
258
259 #ifndef _WIN32
260 {
261 r = uv_tcp_init(uv_default_loop(), &client2);
262 ASSERT(r == 0);
263
264 r = uv_tcp_open(&client2, sock);
265 ASSERT(r == UV_EEXIST);
266
267 uv_close((uv_handle_t*) &client2, NULL);
268 }
269 #else /* _WIN32 */
270 (void)client2;
271 #endif
272
273 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
274
275 ASSERT(shutdown_cb_called == 1);
276 ASSERT(connect_cb_called == 1);
277 ASSERT(write_cb_called == 1);
278 ASSERT(close_cb_called == 1);
279
280 MAKE_VALGRIND_HAPPY();
281 return 0;
282 }
283
284
TEST_IMPL(tcp_open_twice)285 TEST_IMPL(tcp_open_twice) {
286 uv_tcp_t client;
287 uv_os_sock_t sock1, sock2;
288 int r;
289
290 startup();
291 sock1 = create_tcp_socket();
292 sock2 = create_tcp_socket();
293
294 r = uv_tcp_init(uv_default_loop(), &client);
295 ASSERT(r == 0);
296
297 r = uv_tcp_open(&client, sock1);
298 ASSERT(r == 0);
299
300 r = uv_tcp_open(&client, sock2);
301 ASSERT(r == UV_EBUSY);
302 close_socket(sock2);
303
304 uv_close((uv_handle_t*) &client, NULL);
305 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
306
307 MAKE_VALGRIND_HAPPY();
308 return 0;
309 }
310
311
TEST_IMPL(tcp_open_bound)312 TEST_IMPL(tcp_open_bound) {
313 struct sockaddr_in addr;
314 uv_tcp_t server;
315 uv_os_sock_t sock;
316
317 startup();
318 sock = create_tcp_socket();
319
320 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
321
322 ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
323
324 ASSERT(0 == bind(sock, (struct sockaddr*) &addr, sizeof(addr)));
325
326 ASSERT(0 == uv_tcp_open(&server, sock));
327
328 ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, NULL));
329
330 MAKE_VALGRIND_HAPPY();
331 return 0;
332 }
333
334
TEST_IMPL(tcp_open_connected)335 TEST_IMPL(tcp_open_connected) {
336 struct sockaddr_in addr;
337 uv_tcp_t client;
338 uv_os_sock_t sock;
339 uv_buf_t buf = uv_buf_init("PING", 4);
340
341 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
342
343 startup();
344 sock = create_tcp_socket();
345
346 ASSERT(0 == connect(sock, (struct sockaddr*) &addr, sizeof(addr)));
347
348 ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
349
350 ASSERT(0 == uv_tcp_open(&client, sock));
351
352 ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &client, &buf, 1, write_cb));
353
354 ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) &client, shutdown_cb));
355
356 ASSERT(0 == uv_read_start((uv_stream_t*) &client, alloc_cb, read_cb));
357
358 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
359
360 ASSERT(shutdown_cb_called == 1);
361 ASSERT(write_cb_called == 1);
362 ASSERT(close_cb_called == 1);
363
364 MAKE_VALGRIND_HAPPY();
365 return 0;
366 }
367
368
TEST_IMPL(tcp_write_ready)369 TEST_IMPL(tcp_write_ready) {
370 struct sockaddr_in addr;
371 uv_os_sock_t sock;
372 int r;
373
374 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
375
376 startup();
377 sock = create_tcp_socket();
378
379 r = uv_tcp_init(uv_default_loop(), &client);
380 ASSERT(r == 0);
381
382 r = uv_tcp_open(&client, sock);
383 ASSERT(r == 0);
384
385 r = uv_tcp_connect(&connect_req,
386 &client,
387 (const struct sockaddr*) &addr,
388 connect1_cb);
389 ASSERT(r == 0);
390
391 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
392
393 ASSERT(shutdown_cb_called == 1);
394 ASSERT(shutdown_requested == 1);
395 ASSERT(connect_cb_called == 1);
396 ASSERT(write_cb_called > 0);
397 ASSERT(close_cb_called == 1);
398
399 MAKE_VALGRIND_HAPPY();
400 return 0;
401 }
402