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
27
28 static int connect_cb_called = 0;
29 static int close_cb_called = 0;
30
31
close_cb(uv_handle_t * handle)32 static void close_cb(uv_handle_t* handle) {
33 ASSERT_NOT_NULL(handle);
34 close_cb_called++;
35 }
36
37
connect_cb(uv_connect_t * req,int status)38 static void connect_cb(uv_connect_t* req, int status) {
39 ASSERT(status == UV_EADDRINUSE);
40 uv_close((uv_handle_t*) req->handle, close_cb);
41 connect_cb_called++;
42 }
43
44
TEST_IMPL(tcp_bind_error_addrinuse_connect)45 TEST_IMPL(tcp_bind_error_addrinuse_connect) {
46 struct sockaddr_in addr;
47 int addrlen;
48 uv_connect_t req;
49 uv_tcp_t conn;
50
51 /* 127.0.0.1:<TEST_PORT> is already taken by tcp4_echo_server running in
52 * another process. uv_tcp_bind() and uv_tcp_connect() should still succeed
53 * (greatest common denominator across platforms) but the connect callback
54 * should receive an UV_EADDRINUSE error.
55 */
56 ASSERT(0 == uv_tcp_init(uv_default_loop(), &conn));
57 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
58 ASSERT(0 == uv_tcp_bind(&conn, (const struct sockaddr*) &addr, 0));
59
60 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT + 1, &addr));
61 ASSERT(0 == uv_tcp_connect(&req,
62 &conn,
63 (const struct sockaddr*) &addr,
64 connect_cb));
65
66 addrlen = sizeof(addr);
67 ASSERT(UV_EADDRINUSE == uv_tcp_getsockname(&conn,
68 (struct sockaddr*) &addr,
69 &addrlen));
70
71 ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
72 ASSERT(connect_cb_called == 1);
73 ASSERT(close_cb_called == 1);
74
75 MAKE_VALGRIND_HAPPY();
76 return 0;
77 }
78
79
TEST_IMPL(tcp_bind_error_addrinuse_listen)80 TEST_IMPL(tcp_bind_error_addrinuse_listen) {
81 struct sockaddr_in addr;
82 uv_tcp_t server1, server2;
83 int r;
84
85 ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
86 r = uv_tcp_init(uv_default_loop(), &server1);
87 ASSERT(r == 0);
88 r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
89 ASSERT(r == 0);
90
91 r = uv_tcp_init(uv_default_loop(), &server2);
92 ASSERT(r == 0);
93 r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
94 ASSERT(r == 0);
95
96 r = uv_listen((uv_stream_t*)&server1, 128, NULL);
97 ASSERT(r == 0);
98 r = uv_listen((uv_stream_t*)&server2, 128, NULL);
99 ASSERT(r == UV_EADDRINUSE);
100
101 uv_close((uv_handle_t*)&server1, close_cb);
102 uv_close((uv_handle_t*)&server2, close_cb);
103
104 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
105
106 ASSERT(close_cb_called == 2);
107
108 MAKE_VALGRIND_HAPPY();
109 return 0;
110 }
111
112
TEST_IMPL(tcp_bind_error_addrnotavail_1)113 TEST_IMPL(tcp_bind_error_addrnotavail_1) {
114 struct sockaddr_in addr;
115 uv_tcp_t server;
116 int r;
117
118 ASSERT(0 == uv_ip4_addr("127.255.255.255", TEST_PORT, &addr));
119
120 r = uv_tcp_init(uv_default_loop(), &server);
121 ASSERT(r == 0);
122
123 /* It seems that Linux is broken here - bind succeeds. */
124 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
125 ASSERT(r == 0 || r == UV_EADDRNOTAVAIL);
126
127 uv_close((uv_handle_t*)&server, close_cb);
128
129 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
130
131 ASSERT(close_cb_called == 1);
132
133 MAKE_VALGRIND_HAPPY();
134 return 0;
135 }
136
137
TEST_IMPL(tcp_bind_error_addrnotavail_2)138 TEST_IMPL(tcp_bind_error_addrnotavail_2) {
139 struct sockaddr_in addr;
140 uv_tcp_t server;
141 int r;
142
143 ASSERT(0 == uv_ip4_addr("4.4.4.4", TEST_PORT, &addr));
144
145 r = uv_tcp_init(uv_default_loop(), &server);
146 ASSERT(r == 0);
147 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
148 ASSERT(r == UV_EADDRNOTAVAIL);
149
150 uv_close((uv_handle_t*)&server, close_cb);
151
152 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
153
154 ASSERT(close_cb_called == 1);
155
156 MAKE_VALGRIND_HAPPY();
157 return 0;
158 }
159
160
TEST_IMPL(tcp_bind_error_fault)161 TEST_IMPL(tcp_bind_error_fault) {
162 char garbage[] =
163 "blah blah blah blah blah blah blah blah blah blah blah blah";
164 struct sockaddr_in* garbage_addr;
165 uv_tcp_t server;
166 int r;
167
168 garbage_addr = (struct sockaddr_in*) &garbage;
169
170 r = uv_tcp_init(uv_default_loop(), &server);
171 ASSERT(r == 0);
172 r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
173 ASSERT(r == UV_EINVAL);
174
175 uv_close((uv_handle_t*)&server, close_cb);
176
177 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
178
179 ASSERT(close_cb_called == 1);
180
181 MAKE_VALGRIND_HAPPY();
182 return 0;
183 }
184
185 /* Notes: On Linux uv_bind(server, NULL) will segfault the program. */
186
TEST_IMPL(tcp_bind_error_inval)187 TEST_IMPL(tcp_bind_error_inval) {
188 struct sockaddr_in addr1;
189 struct sockaddr_in addr2;
190 uv_tcp_t server;
191 int r;
192
193 ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr1));
194 ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT_2, &addr2));
195
196 r = uv_tcp_init(uv_default_loop(), &server);
197 ASSERT(r == 0);
198 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
199 ASSERT(r == 0);
200 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
201 ASSERT(r == UV_EINVAL);
202
203 uv_close((uv_handle_t*)&server, close_cb);
204
205 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
206
207 ASSERT(close_cb_called == 1);
208
209 MAKE_VALGRIND_HAPPY();
210 return 0;
211 }
212
213
TEST_IMPL(tcp_bind_localhost_ok)214 TEST_IMPL(tcp_bind_localhost_ok) {
215 struct sockaddr_in addr;
216 uv_tcp_t server;
217 int r;
218
219 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
220
221 r = uv_tcp_init(uv_default_loop(), &server);
222 ASSERT(r == 0);
223 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
224 ASSERT(r == 0);
225
226 MAKE_VALGRIND_HAPPY();
227 return 0;
228 }
229
230
TEST_IMPL(tcp_bind_invalid_flags)231 TEST_IMPL(tcp_bind_invalid_flags) {
232 struct sockaddr_in addr;
233 uv_tcp_t server;
234 int r;
235
236 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
237
238 r = uv_tcp_init(uv_default_loop(), &server);
239 ASSERT(r == 0);
240 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, UV_TCP_IPV6ONLY);
241 ASSERT(r == UV_EINVAL);
242
243 MAKE_VALGRIND_HAPPY();
244 return 0;
245 }
246
247
TEST_IMPL(tcp_listen_without_bind)248 TEST_IMPL(tcp_listen_without_bind) {
249 int r;
250 uv_tcp_t server;
251
252 r = uv_tcp_init(uv_default_loop(), &server);
253 ASSERT(r == 0);
254 r = uv_listen((uv_stream_t*)&server, 128, NULL);
255 ASSERT(r == 0);
256
257 MAKE_VALGRIND_HAPPY();
258 return 0;
259 }
260
261
TEST_IMPL(tcp_bind_writable_flags)262 TEST_IMPL(tcp_bind_writable_flags) {
263 struct sockaddr_in addr;
264 uv_tcp_t server;
265 uv_buf_t buf;
266 uv_write_t write_req;
267 uv_shutdown_t shutdown_req;
268 int r;
269
270 ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
271 r = uv_tcp_init(uv_default_loop(), &server);
272 ASSERT(r == 0);
273 r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
274 ASSERT(r == 0);
275 r = uv_listen((uv_stream_t*)&server, 128, NULL);
276 ASSERT(r == 0);
277
278 ASSERT(0 == uv_is_writable((uv_stream_t*) &server));
279 ASSERT(0 == uv_is_readable((uv_stream_t*) &server));
280
281 buf = uv_buf_init("PING", 4);
282 r = uv_write(&write_req, (uv_stream_t*) &server, &buf, 1, NULL);
283 ASSERT(r == UV_EPIPE);
284 r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL);
285 ASSERT(r == UV_ENOTCONN);
286 r = uv_read_start((uv_stream_t*) &server,
287 (uv_alloc_cb) abort,
288 (uv_read_cb) abort);
289 ASSERT(r == UV_ENOTCONN);
290
291 uv_close((uv_handle_t*)&server, close_cb);
292
293 uv_run(uv_default_loop(), UV_RUN_DEFAULT);
294
295 ASSERT(close_cb_called == 1);
296
297 MAKE_VALGRIND_HAPPY();
298 return 0;
299 }
300
TEST_IMPL(tcp_bind_or_listen_error_after_close)301 TEST_IMPL(tcp_bind_or_listen_error_after_close) {
302 uv_tcp_t tcp;
303 struct sockaddr_in addr;
304
305 memset(&addr, 0, sizeof(addr));
306 addr.sin_addr.s_addr = htonl(INADDR_ANY);
307 addr.sin_port = htons(9999);
308 addr.sin_family = AF_INET;
309
310 ASSERT_EQ(uv_tcp_init(uv_default_loop(), &tcp), 0);
311 uv_close((uv_handle_t*) &tcp, NULL);
312 ASSERT_EQ(uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0), UV_EINVAL);
313 ASSERT_EQ(uv_listen((uv_stream_t*) &tcp, 5, NULL), UV_EINVAL);
314 ASSERT_EQ(uv_run(uv_default_loop(), UV_RUN_DEFAULT), 0);
315 MAKE_VALGRIND_HAPPY();
316 return 0;
317 }
318