1 /* Copyright libuv project 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 static uv_tcp_t server;
26 static uv_tcp_t connection;
27 static int read_cb_called = 0;
28
29 static uv_tcp_t client;
30 static uv_connect_t connect_req;
31
32
33 static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
34
on_write_close_immediately(uv_write_t * req,int status)35 static void on_write_close_immediately(uv_write_t* req, int status) {
36 ASSERT(0 == status);
37
38 uv_close((uv_handle_t*)req->handle, NULL); /* Close immediately */
39 free(req);
40 }
41
on_write(uv_write_t * req,int status)42 static void on_write(uv_write_t* req, int status) {
43 ASSERT(0 == status);
44
45 free(req);
46 }
47
do_write(uv_stream_t * stream,uv_write_cb cb)48 static void do_write(uv_stream_t* stream, uv_write_cb cb) {
49 uv_write_t* req = malloc(sizeof(*req));
50 uv_buf_t buf;
51 buf.base = "1234578";
52 buf.len = 8;
53 ASSERT(0 == uv_write(req, stream, &buf, 1, cb));
54 }
55
on_alloc(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)56 static void on_alloc(uv_handle_t* handle,
57 size_t suggested_size,
58 uv_buf_t* buf) {
59 static char slab[65536];
60 buf->base = slab;
61 buf->len = sizeof(slab);
62 }
63
on_read1(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)64 static void on_read1(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
65 ASSERT(nread >= 0);
66
67 /* Do write on a half open connection to force WSAECONNABORTED (on Windows)
68 * in the subsequent uv_read_start()
69 */
70 do_write(stream, on_write);
71
72 ASSERT(0 == uv_read_stop(stream));
73
74 ASSERT(0 == uv_read_start(stream, on_alloc, on_read2));
75
76 read_cb_called++;
77 }
78
on_read2(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)79 static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
80 ASSERT(nread < 0);
81
82 uv_close((uv_handle_t*)stream, NULL);
83 uv_close((uv_handle_t*)&server, NULL);
84
85 read_cb_called++;
86 }
87
on_connection(uv_stream_t * server,int status)88 static void on_connection(uv_stream_t* server, int status) {
89 ASSERT(0 == status);
90
91 ASSERT(0 == uv_tcp_init(server->loop, &connection));
92
93 ASSERT(0 == uv_accept(server, (uv_stream_t* )&connection));
94
95 ASSERT(0 == uv_read_start((uv_stream_t*)&connection, on_alloc, on_read1));
96 }
97
on_connect(uv_connect_t * req,int status)98 static void on_connect(uv_connect_t* req, int status) {
99 ASSERT(0 == status);
100
101 do_write((uv_stream_t*)&client, on_write_close_immediately);
102 }
103
TEST_IMPL(tcp_read_stop_start)104 TEST_IMPL(tcp_read_stop_start) {
105 uv_loop_t* loop = uv_default_loop();
106
107 { /* Server */
108 struct sockaddr_in addr;
109
110 ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
111
112 ASSERT(0 == uv_tcp_init(loop, &server));
113
114 ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) & addr, 0));
115
116 ASSERT(0 == uv_listen((uv_stream_t*)&server, 10, on_connection));
117 }
118
119 { /* Client */
120 struct sockaddr_in addr;
121
122 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
123
124 ASSERT(0 == uv_tcp_init(loop, &client));
125
126 ASSERT(0 == uv_tcp_connect(&connect_req, &client,
127 (const struct sockaddr*) & addr, on_connect));
128 }
129
130 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
131
132 ASSERT(read_cb_called >= 2);
133
134 MAKE_VALGRIND_HAPPY();
135 return 0;
136 }
137