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 25static uv_tcp_t server; 26static uv_tcp_t connection; 27static int read_cb_called = 0; 28 29static uv_tcp_t client; 30static uv_connect_t connect_req; 31 32 33static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); 34 35static void on_write_close_immediately(uv_write_t* req, int status) { 36 ASSERT_OK(status); 37 38 uv_close((uv_handle_t*)req->handle, NULL); /* Close immediately */ 39 free(req); 40} 41 42static void on_write(uv_write_t* req, int status) { 43 ASSERT_OK(status); 44 45 free(req); 46} 47 48static 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_OK(uv_write(req, stream, &buf, 1, cb)); 54} 55 56static 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 64static void on_read1(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { 65 ASSERT_GE(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_OK(uv_read_stop(stream)); 73 74 ASSERT_OK(uv_read_start(stream, on_alloc, on_read2)); 75 76 read_cb_called++; 77} 78 79static void on_read2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { 80 ASSERT_LT(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 88static void on_connection(uv_stream_t* server, int status) { 89 ASSERT_OK(status); 90 91 ASSERT_OK(uv_tcp_init(server->loop, &connection)); 92 93 ASSERT_OK(uv_accept(server, (uv_stream_t* )&connection)); 94 95 ASSERT_OK(uv_read_start((uv_stream_t*)&connection, on_alloc, on_read1)); 96} 97 98static void on_connect(uv_connect_t* req, int status) { 99 ASSERT_OK(status); 100 101 do_write((uv_stream_t*)&client, on_write_close_immediately); 102} 103 104TEST_IMPL(tcp_read_stop_start) { 105 uv_loop_t* loop = uv_default_loop(); 106 107 { /* Server */ 108 struct sockaddr_in addr; 109 110 ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); 111 112 ASSERT_OK(uv_tcp_init(loop, &server)); 113 114 ASSERT_OK(uv_tcp_bind(&server, (struct sockaddr*) & addr, 0)); 115 116 ASSERT_OK(uv_listen((uv_stream_t*)&server, 10, on_connection)); 117 } 118 119 { /* Client */ 120 struct sockaddr_in addr; 121 122 ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 123 124 ASSERT_OK(uv_tcp_init(loop, &client)); 125 126 ASSERT_OK(uv_tcp_connect(&connect_req, &client, 127 (const struct sockaddr*) & addr, on_connect)); 128 } 129 130 ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); 131 132 ASSERT_GE(read_cb_called, 2); 133 134 MAKE_VALGRIND_HAPPY(loop); 135 return 0; 136} 137