libuv-svace-build
439 строк · 11.1 Кб
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
25#include <stdio.h>26#include <stdlib.h>27#include <string.h> /* strlen */28
29static int completed_pingers = 0;30
31#if defined(__CYGWIN__) || defined(__MSYS__) || defined(__MVS__)32#define NUM_PINGS 100 /* fewer pings to avoid timeout */33#else34#define NUM_PINGS 100035#endif36
37static char PING[] = "PING\n";38static char PONG[] = "PONG\n";39static int pinger_on_connect_count;40
41
42typedef struct {43int vectored_writes;44unsigned pongs;45unsigned state;46union {47uv_tcp_t tcp;48uv_pipe_t pipe;49} stream;50uv_connect_t connect_req;51char* pong;52} pinger_t;53
54
55static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {56buf->base = malloc(size);57buf->len = size;58}
59
60
61static void ponger_on_close(uv_handle_t* handle) {62if (handle->data)63free(handle->data);64else65free(handle);66}
67
68
69static void pinger_on_close(uv_handle_t* handle) {70pinger_t* pinger = (pinger_t*) handle->data;71
72ASSERT_EQ(NUM_PINGS, pinger->pongs);73
74if (handle == (uv_handle_t*) &pinger->stream.tcp) {75free(pinger); /* also frees handle */76} else {77uv_close((uv_handle_t*) &pinger->stream.tcp, ponger_on_close);78free(handle);79}80
81completed_pingers++;82}
83
84
85static void pinger_after_write(uv_write_t* req, int status) {86ASSERT_OK(status);87free(req->data);88free(req);89}
90
91
92static void pinger_write_ping(pinger_t* pinger) {93uv_stream_t* stream;94uv_write_t* req;95uv_buf_t bufs[sizeof PING - 1];96int i, nbufs;97
98stream = (uv_stream_t*) &pinger->stream.tcp;99
100if (!pinger->vectored_writes) {101/* Write a single buffer. */102nbufs = 1;103bufs[0] = uv_buf_init(PING, sizeof PING - 1);104} else {105/* Write multiple buffers, each with one byte in them. */106nbufs = sizeof PING - 1;107for (i = 0; i < nbufs; i++) {108bufs[i] = uv_buf_init(&PING[i], 1);109}110}111
112req = malloc(sizeof(*req));113ASSERT_NOT_NULL(req);114req->data = NULL;115ASSERT_OK(uv_write(req, stream, bufs, nbufs, pinger_after_write));116
117puts("PING");118}
119
120
121static void pinger_read_cb(uv_stream_t* stream,122ssize_t nread,123const uv_buf_t* buf) {124ssize_t i;125pinger_t* pinger;126
127pinger = (pinger_t*) stream->data;128
129if (nread < 0) {130ASSERT_EQ(nread, UV_EOF);131
132puts("got EOF");133free(buf->base);134
135uv_close((uv_handle_t*) stream, pinger_on_close);136
137return;138}139
140/* Now we count the pongs */141for (i = 0; i < nread; i++) {142ASSERT_EQ(buf->base[i], pinger->pong[pinger->state]);143pinger->state = (pinger->state + 1) % strlen(pinger->pong);144
145if (pinger->state != 0)146continue;147
148printf("PONG %d\n", pinger->pongs);149pinger->pongs++;150
151if (pinger->pongs < NUM_PINGS) {152pinger_write_ping(pinger);153} else {154uv_close((uv_handle_t*) stream, pinger_on_close);155break;156}157}158
159free(buf->base);160}
161
162
163static void ponger_read_cb(uv_stream_t* stream,164ssize_t nread,165const uv_buf_t* buf) {166uv_buf_t writebuf;167uv_write_t* req;168int i;169
170if (nread < 0) {171ASSERT_EQ(nread, UV_EOF);172
173puts("got EOF");174free(buf->base);175
176uv_close((uv_handle_t*) stream, ponger_on_close);177
178return;179}180
181/* Echo back */182for (i = 0; i < nread; i++) {183if (buf->base[i] == 'I')184buf->base[i] = 'O';185}186
187writebuf = uv_buf_init(buf->base, nread);188req = malloc(sizeof(*req));189ASSERT_NOT_NULL(req);190req->data = buf->base;191ASSERT_OK(uv_write(req, stream, &writebuf, 1, pinger_after_write));192}
193
194
195static void pinger_on_connect(uv_connect_t* req, int status) {196pinger_t* pinger = (pinger_t*) req->handle->data;197
198pinger_on_connect_count++;199
200ASSERT_OK(status);201
202ASSERT_EQ(1, uv_is_readable(req->handle));203ASSERT_EQ(1, uv_is_writable(req->handle));204ASSERT_OK(uv_is_closing((uv_handle_t *) req->handle));205
206pinger_write_ping(pinger);207
208ASSERT_OK(uv_read_start((uv_stream_t*) req->handle,209alloc_cb,210pinger_read_cb));211}
212
213
214/* same ping-pong test, but using IPv6 connection */
215static void tcp_pinger_v6_new(int vectored_writes) {216int r;217struct sockaddr_in6 server_addr;218pinger_t* pinger;219
220
221ASSERT_OK(uv_ip6_addr("::1", TEST_PORT, &server_addr));222pinger = malloc(sizeof(*pinger));223ASSERT_NOT_NULL(pinger);224pinger->vectored_writes = vectored_writes;225pinger->state = 0;226pinger->pongs = 0;227pinger->pong = PING;228
229/* Try to connect to the server and do NUM_PINGS ping-pongs. */230r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);231pinger->stream.tcp.data = pinger;232ASSERT_OK(r);233
234/* We are never doing multiple reads/connects at a time anyway, so these235* handles can be pre-initialized. */
236r = uv_tcp_connect(&pinger->connect_req,237&pinger->stream.tcp,238(const struct sockaddr*) &server_addr,239pinger_on_connect);240ASSERT_OK(r);241
242/* Synchronous connect callbacks are not allowed. */243ASSERT_OK(pinger_on_connect_count);244}
245
246
247static void tcp_pinger_new(int vectored_writes) {248int r;249struct sockaddr_in server_addr;250pinger_t* pinger;251
252ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));253pinger = malloc(sizeof(*pinger));254ASSERT_NOT_NULL(pinger);255pinger->vectored_writes = vectored_writes;256pinger->state = 0;257pinger->pongs = 0;258pinger->pong = PING;259
260/* Try to connect to the server and do NUM_PINGS ping-pongs. */261r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);262pinger->stream.tcp.data = pinger;263ASSERT_OK(r);264
265/* We are never doing multiple reads/connects at a time anyway, so these266* handles can be pre-initialized. */
267r = uv_tcp_connect(&pinger->connect_req,268&pinger->stream.tcp,269(const struct sockaddr*) &server_addr,270pinger_on_connect);271ASSERT_OK(r);272
273/* Synchronous connect callbacks are not allowed. */274ASSERT_OK(pinger_on_connect_count);275}
276
277
278static void pipe_pinger_new(int vectored_writes) {279int r;280pinger_t* pinger;281
282pinger = malloc(sizeof(*pinger));283ASSERT_NOT_NULL(pinger);284pinger->vectored_writes = vectored_writes;285pinger->state = 0;286pinger->pongs = 0;287pinger->pong = PING;288
289/* Try to connect to the server and do NUM_PINGS ping-pongs. */290r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);291pinger->stream.pipe.data = pinger;292ASSERT_OK(r);293
294/* We are never doing multiple reads/connects at a time anyway, so these295* handles can be pre-initialized. */
296uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,297pinger_on_connect);298
299/* Synchronous connect callbacks are not allowed. */300ASSERT_OK(pinger_on_connect_count);301}
302
303
304static void socketpair_pinger_new(int vectored_writes) {305pinger_t* pinger;306uv_os_sock_t fds[2];307uv_tcp_t* ponger;308
309pinger = malloc(sizeof(*pinger));310ASSERT_NOT_NULL(pinger);311pinger->vectored_writes = vectored_writes;312pinger->state = 0;313pinger->pongs = 0;314pinger->pong = PONG;315
316/* Try to make a socketpair and do NUM_PINGS ping-pongs. */317(void)uv_default_loop(); /* ensure WSAStartup has been performed */318ASSERT_OK(uv_socketpair(SOCK_STREAM, 0, fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE));319#ifndef _WIN32320/* On Windows, this is actually a UV_TCP, but libuv doesn't detect that. */321ASSERT_EQ(uv_guess_handle((uv_file) fds[0]), UV_NAMED_PIPE);322ASSERT_EQ(uv_guess_handle((uv_file) fds[1]), UV_NAMED_PIPE);323#endif324
325ASSERT_OK(uv_tcp_init(uv_default_loop(), &pinger->stream.tcp));326pinger->stream.pipe.data = pinger;327ASSERT_OK(uv_tcp_open(&pinger->stream.tcp, fds[1]));328
329ponger = malloc(sizeof(*ponger));330ASSERT_NOT_NULL(ponger);331ponger->data = NULL;332ASSERT_OK(uv_tcp_init(uv_default_loop(), ponger));333ASSERT_OK(uv_tcp_open(ponger, fds[0]));334
335pinger_write_ping(pinger);336
337ASSERT_OK(uv_read_start((uv_stream_t*) &pinger->stream.tcp,338alloc_cb,339pinger_read_cb));340ASSERT_OK(uv_read_start((uv_stream_t*) ponger,341alloc_cb,342ponger_read_cb));343}
344
345
346static void pipe2_pinger_new(int vectored_writes) {347uv_file fds[2];348pinger_t* pinger;349uv_pipe_t* ponger;350
351/* Try to make a pipe and do NUM_PINGS pings. */352ASSERT_OK(uv_pipe(fds, UV_NONBLOCK_PIPE, UV_NONBLOCK_PIPE));353ASSERT_EQ(uv_guess_handle(fds[0]), UV_NAMED_PIPE);354ASSERT_EQ(uv_guess_handle(fds[1]), UV_NAMED_PIPE);355
356ponger = malloc(sizeof(*ponger));357ASSERT_NOT_NULL(ponger);358ASSERT_OK(uv_pipe_init(uv_default_loop(), ponger, 0));359ASSERT_OK(uv_pipe_open(ponger, fds[0]));360
361pinger = malloc(sizeof(*pinger));362ASSERT_NOT_NULL(pinger);363pinger->vectored_writes = vectored_writes;364pinger->state = 0;365pinger->pongs = 0;366pinger->pong = PING;367ASSERT_OK(uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0));368ASSERT_OK(uv_pipe_open(&pinger->stream.pipe, fds[1]));369pinger->stream.pipe.data = pinger; /* record for close_cb */370ponger->data = pinger; /* record for read_cb */371
372pinger_write_ping(pinger);373
374ASSERT_OK(uv_read_start((uv_stream_t*) ponger, alloc_cb, pinger_read_cb));375}
376
377static int run_ping_pong_test(void) {378uv_run(uv_default_loop(), UV_RUN_DEFAULT);379ASSERT_EQ(1, completed_pingers);380
381MAKE_VALGRIND_HAPPY(uv_default_loop());382return 0;383}
384
385
386TEST_IMPL(tcp_ping_pong) {387tcp_pinger_new(0);388run_ping_pong_test();389
390completed_pingers = 0;391socketpair_pinger_new(0);392return run_ping_pong_test();393}
394
395
396TEST_IMPL(tcp_ping_pong_vec) {397tcp_pinger_new(1);398run_ping_pong_test();399
400completed_pingers = 0;401socketpair_pinger_new(1);402return run_ping_pong_test();403}
404
405
406TEST_IMPL(tcp6_ping_pong) {407if (!can_ipv6())408RETURN_SKIP("IPv6 not supported");409tcp_pinger_v6_new(0);410return run_ping_pong_test();411}
412
413
414TEST_IMPL(tcp6_ping_pong_vec) {415if (!can_ipv6())416RETURN_SKIP("IPv6 not supported");417tcp_pinger_v6_new(1);418return run_ping_pong_test();419}
420
421
422TEST_IMPL(pipe_ping_pong) {423pipe_pinger_new(0);424run_ping_pong_test();425
426completed_pingers = 0;427pipe2_pinger_new(0);428return run_ping_pong_test();429}
430
431
432TEST_IMPL(pipe_ping_pong_vec) {433pipe_pinger_new(1);434run_ping_pong_test();435
436completed_pingers = 0;437pipe2_pinger_new(1);438return run_ping_pong_test();439}
440