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 typedef struct {
28 uv_write_t req;
29 uv_buf_t buf;
30 } write_req_t;
31
32 static uv_loop_t* loop;
33
34 static int server_closed;
35 static stream_type serverType;
36 static uv_tcp_t tcpServer;
37 static uv_udp_t udpServer;
38 static uv_pipe_t pipeServer;
39 static uv_handle_t* server;
40 static uv_udp_send_t* send_freelist;
41
42 static void after_write(uv_write_t* req, int status);
43 static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
44 static void on_close(uv_handle_t* peer);
45 static void on_server_close(uv_handle_t* handle);
46 static void on_connection(uv_stream_t*, int status);
47
48
after_write(uv_write_t * req,int status)49 static void after_write(uv_write_t* req, int status) {
50 write_req_t* wr;
51
52 /* Free the read/write buffer and the request */
53 wr = (write_req_t*) req;
54 free(wr->buf.base);
55 free(wr);
56
57 if (status == 0)
58 return;
59
60 fprintf(stderr,
61 "uv_write error: %s - %s\n",
62 uv_err_name(status),
63 uv_strerror(status));
64 }
65
66
after_shutdown(uv_shutdown_t * req,int status)67 static void after_shutdown(uv_shutdown_t* req, int status) {
68 uv_close((uv_handle_t*) req->handle, on_close);
69 free(req);
70 }
71
72
after_read(uv_stream_t * handle,ssize_t nread,const uv_buf_t * buf)73 static void after_read(uv_stream_t* handle,
74 ssize_t nread,
75 const uv_buf_t* buf) {
76 int i;
77 write_req_t *wr;
78 uv_shutdown_t* sreq;
79
80 if (nread < 0) {
81 /* Error or EOF */
82 ASSERT(nread == UV_EOF);
83
84 free(buf->base);
85 sreq = malloc(sizeof* sreq);
86 ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown));
87 return;
88 }
89
90 if (nread == 0) {
91 /* Everything OK, but nothing read. */
92 free(buf->base);
93 return;
94 }
95
96 /*
97 * Scan for the letter Q which signals that we should quit the server.
98 * If we get QS it means close the stream.
99 */
100 if (!server_closed) {
101 for (i = 0; i < nread; i++) {
102 if (buf->base[i] == 'Q') {
103 if (i + 1 < nread && buf->base[i + 1] == 'S') {
104 free(buf->base);
105 uv_close((uv_handle_t*)handle, on_close);
106 return;
107 } else {
108 uv_close(server, on_server_close);
109 server_closed = 1;
110 }
111 }
112 }
113 }
114
115 wr = (write_req_t*) malloc(sizeof *wr);
116 ASSERT(wr != NULL);
117 wr->buf = uv_buf_init(buf->base, nread);
118
119 if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
120 FATAL("uv_write failed");
121 }
122 }
123
124
on_close(uv_handle_t * peer)125 static void on_close(uv_handle_t* peer) {
126 free(peer);
127 }
128
129
echo_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)130 static void echo_alloc(uv_handle_t* handle,
131 size_t suggested_size,
132 uv_buf_t* buf) {
133 buf->base = malloc(suggested_size);
134 buf->len = suggested_size;
135 }
136
slab_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)137 static void slab_alloc(uv_handle_t* handle,
138 size_t suggested_size,
139 uv_buf_t* buf) {
140 /* up to 16 datagrams at once */
141 static char slab[16 * 64 * 1024];
142 buf->base = slab;
143 buf->len = sizeof(slab);
144 }
145
on_connection(uv_stream_t * server,int status)146 static void on_connection(uv_stream_t* server, int status) {
147 uv_stream_t* stream;
148 int r;
149
150 if (status != 0) {
151 fprintf(stderr, "Connect error %s\n", uv_err_name(status));
152 }
153 ASSERT(status == 0);
154
155 switch (serverType) {
156 case TCP:
157 stream = malloc(sizeof(uv_tcp_t));
158 ASSERT(stream != NULL);
159 r = uv_tcp_init(loop, (uv_tcp_t*)stream);
160 ASSERT(r == 0);
161 break;
162
163 case PIPE:
164 stream = malloc(sizeof(uv_pipe_t));
165 ASSERT(stream != NULL);
166 r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
167 ASSERT(r == 0);
168 break;
169
170 default:
171 ASSERT(0 && "Bad serverType");
172 abort();
173 }
174
175 /* associate server with stream */
176 stream->data = server;
177
178 r = uv_accept(server, stream);
179 ASSERT(r == 0);
180
181 r = uv_read_start(stream, echo_alloc, after_read);
182 ASSERT(r == 0);
183 }
184
185
on_server_close(uv_handle_t * handle)186 static void on_server_close(uv_handle_t* handle) {
187 ASSERT(handle == server);
188 }
189
send_alloc(void)190 static uv_udp_send_t* send_alloc(void) {
191 uv_udp_send_t* req = send_freelist;
192 if (req != NULL)
193 send_freelist = req->data;
194 else
195 req = malloc(sizeof(*req));
196 return req;
197 }
198
on_send(uv_udp_send_t * req,int status)199 static void on_send(uv_udp_send_t* req, int status) {
200 ASSERT(req != NULL);
201 ASSERT(status == 0);
202 req->data = send_freelist;
203 send_freelist = req;
204 }
205
on_recv(uv_udp_t * handle,ssize_t nread,const uv_buf_t * rcvbuf,const struct sockaddr * addr,unsigned flags)206 static void on_recv(uv_udp_t* handle,
207 ssize_t nread,
208 const uv_buf_t* rcvbuf,
209 const struct sockaddr* addr,
210 unsigned flags) {
211 uv_buf_t sndbuf;
212
213 if (nread == 0) {
214 /* Everything OK, but nothing read. */
215 return;
216 }
217
218 ASSERT(nread > 0);
219 ASSERT(addr->sa_family == AF_INET);
220
221 uv_udp_send_t* req = send_alloc();
222 ASSERT(req != NULL);
223 sndbuf = uv_buf_init(rcvbuf->base, nread);
224 ASSERT(0 <= uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
225 }
226
tcp4_echo_start(int port)227 static int tcp4_echo_start(int port) {
228 struct sockaddr_in addr;
229 int r;
230
231 ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
232
233 server = (uv_handle_t*)&tcpServer;
234 serverType = TCP;
235
236 r = uv_tcp_init(loop, &tcpServer);
237 if (r) {
238 /* TODO: Error codes */
239 fprintf(stderr, "Socket creation error\n");
240 return 1;
241 }
242
243 r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
244 if (r) {
245 /* TODO: Error codes */
246 fprintf(stderr, "Bind error\n");
247 return 1;
248 }
249
250 r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
251 if (r) {
252 /* TODO: Error codes */
253 fprintf(stderr, "Listen error %s\n", uv_err_name(r));
254 return 1;
255 }
256
257 return 0;
258 }
259
260
tcp6_echo_start(int port)261 static int tcp6_echo_start(int port) {
262 struct sockaddr_in6 addr6;
263 int r;
264
265 ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
266
267 server = (uv_handle_t*)&tcpServer;
268 serverType = TCP;
269
270 r = uv_tcp_init(loop, &tcpServer);
271 if (r) {
272 /* TODO: Error codes */
273 fprintf(stderr, "Socket creation error\n");
274 return 1;
275 }
276
277 /* IPv6 is optional as not all platforms support it */
278 r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
279 if (r) {
280 /* show message but return OK */
281 fprintf(stderr, "IPv6 not supported\n");
282 return 0;
283 }
284
285 r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
286 if (r) {
287 /* TODO: Error codes */
288 fprintf(stderr, "Listen error\n");
289 return 1;
290 }
291
292 return 0;
293 }
294
295
udp4_echo_start(int port)296 static int udp4_echo_start(int port) {
297 struct sockaddr_in addr;
298 int r;
299
300 ASSERT(0 == uv_ip4_addr("127.0.0.1", port, &addr));
301 server = (uv_handle_t*)&udpServer;
302 serverType = UDP;
303
304 r = uv_udp_init(loop, &udpServer);
305 if (r) {
306 fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
307 return 1;
308 }
309
310 r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0);
311 if (r) {
312 fprintf(stderr, "uv_udp_bind: %s\n", uv_strerror(r));
313 return 1;
314 }
315
316 r = uv_udp_recv_start(&udpServer, slab_alloc, on_recv);
317 if (r) {
318 fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
319 return 1;
320 }
321
322 return 0;
323 }
324
325
pipe_echo_start(char * pipeName)326 static int pipe_echo_start(char* pipeName) {
327 int r;
328
329 #ifndef _WIN32
330 {
331 uv_fs_t req;
332 uv_fs_unlink(NULL, &req, pipeName, NULL);
333 uv_fs_req_cleanup(&req);
334 }
335 #endif
336
337 server = (uv_handle_t*)&pipeServer;
338 serverType = PIPE;
339
340 r = uv_pipe_init(loop, &pipeServer, 0);
341 if (r) {
342 fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
343 return 1;
344 }
345
346 r = uv_pipe_bind(&pipeServer, pipeName);
347 if (r) {
348 fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
349 return 1;
350 }
351
352 r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
353 if (r) {
354 fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
355 return 1;
356 }
357
358 return 0;
359 }
360
361
HELPER_IMPL(tcp4_echo_server)362 HELPER_IMPL(tcp4_echo_server) {
363 loop = uv_default_loop();
364
365 if (tcp4_echo_start(TEST_PORT))
366 return 1;
367
368 notify_parent_process();
369 uv_run(loop, UV_RUN_DEFAULT);
370 return 0;
371 }
372
373
HELPER_IMPL(tcp6_echo_server)374 HELPER_IMPL(tcp6_echo_server) {
375 loop = uv_default_loop();
376
377 if (tcp6_echo_start(TEST_PORT))
378 return 1;
379
380 notify_parent_process();
381 uv_run(loop, UV_RUN_DEFAULT);
382 return 0;
383 }
384
385
HELPER_IMPL(pipe_echo_server)386 HELPER_IMPL(pipe_echo_server) {
387 loop = uv_default_loop();
388
389 if (pipe_echo_start(TEST_PIPENAME))
390 return 1;
391
392 notify_parent_process();
393 uv_run(loop, UV_RUN_DEFAULT);
394 return 0;
395 }
396
397
HELPER_IMPL(udp4_echo_server)398 HELPER_IMPL(udp4_echo_server) {
399 loop = uv_default_loop();
400
401 if (udp4_echo_start(TEST_PORT))
402 return 1;
403
404 notify_parent_process();
405 uv_run(loop, UV_RUN_DEFAULT);
406 return 0;
407 }
408