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