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 28 #define WRITES 3 29 #if defined(__arm__) /* Decrease the chunks so the test passes on arm CI bots */ 30 #define CHUNKS_PER_WRITE 2048 31 #else 32 #define CHUNKS_PER_WRITE 4096 33 #endif 34 #define CHUNK_SIZE 10024 /* 10 kb */ 35 36 #define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE) 37 38 static char* send_buffer; 39 40 static int shutdown_cb_called = 0; 41 static int connect_cb_called = 0; 42 static int write_cb_called = 0; 43 static int close_cb_called = 0; 44 static size_t bytes_sent = 0; 45 static size_t bytes_sent_done = 0; 46 static size_t bytes_received_done = 0; 47 48 static uv_connect_t connect_req; 49 static uv_shutdown_t shutdown_req; 50 static uv_write_t write_reqs[WRITES]; 51 52 53 static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { 54 buf->base = malloc(size); 55 buf->len = size; 56 } 57 58 59 static void close_cb(uv_handle_t* handle) { 60 ASSERT(handle != NULL); 61 close_cb_called++; 62 } 63 64 65 static void shutdown_cb(uv_shutdown_t* req, int status) { 66 uv_tcp_t* tcp; 67 68 ASSERT(req == &shutdown_req); 69 ASSERT(status == 0); 70 71 tcp = (uv_tcp_t*)(req->handle); 72 73 /* The write buffer should be empty by now. */ 74 ASSERT(tcp->write_queue_size == 0); 75 76 /* Now we wait for the EOF */ 77 shutdown_cb_called++; 78 79 /* We should have had all the writes called already. */ 80 ASSERT(write_cb_called == WRITES); 81 } 82 83 84 static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { 85 ASSERT(tcp != NULL); 86 87 if (nread >= 0) { 88 bytes_received_done += nread; 89 } 90 else { 91 ASSERT(nread == UV_EOF); 92 printf("GOT EOF\n"); 93 uv_close((uv_handle_t*)tcp, close_cb); 94 } 95 96 free(buf->base); 97 } 98 99 100 static void write_cb(uv_write_t* req, int status) { 101 ASSERT(req != NULL); 102 103 if (status) { 104 fprintf(stderr, "uv_write error: %s\n", uv_strerror(status)); 105 ASSERT(0); 106 } 107 108 bytes_sent_done += CHUNKS_PER_WRITE * CHUNK_SIZE; 109 write_cb_called++; 110 } 111 112 113 static void connect_cb(uv_connect_t* req, int status) { 114 uv_buf_t send_bufs[CHUNKS_PER_WRITE]; 115 uv_stream_t* stream; 116 int i, j, r; 117 118 ASSERT(req == &connect_req); 119 ASSERT(status == 0); 120 121 stream = req->handle; 122 connect_cb_called++; 123 124 /* Write a lot of data */ 125 for (i = 0; i < WRITES; i++) { 126 uv_write_t* write_req = write_reqs + i; 127 128 for (j = 0; j < CHUNKS_PER_WRITE; j++) { 129 send_bufs[j] = uv_buf_init(send_buffer + bytes_sent, CHUNK_SIZE); 130 bytes_sent += CHUNK_SIZE; 131 } 132 133 r = uv_write(write_req, stream, send_bufs, CHUNKS_PER_WRITE, write_cb); 134 ASSERT(r == 0); 135 } 136 137 /* Shutdown on drain. */ 138 r = uv_shutdown(&shutdown_req, stream, shutdown_cb); 139 ASSERT(r == 0); 140 141 /* Start reading */ 142 r = uv_read_start(stream, alloc_cb, read_cb); 143 ASSERT(r == 0); 144 } 145 146 147 TEST_IMPL(tcp_writealot) { 148 struct sockaddr_in addr; 149 uv_tcp_t client; 150 int r; 151 152 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 153 154 send_buffer = calloc(1, TOTAL_BYTES); 155 ASSERT(send_buffer != NULL); 156 157 r = uv_tcp_init(uv_default_loop(), &client); 158 ASSERT(r == 0); 159 160 r = uv_tcp_connect(&connect_req, 161 &client, 162 (const struct sockaddr*) &addr, 163 connect_cb); 164 ASSERT(r == 0); 165 166 uv_run(uv_default_loop(), UV_RUN_DEFAULT); 167 168 ASSERT(shutdown_cb_called == 1); 169 ASSERT(connect_cb_called == 1); 170 ASSERT(write_cb_called == WRITES); 171 ASSERT(close_cb_called == 1); 172 ASSERT(bytes_sent == TOTAL_BYTES); 173 ASSERT(bytes_sent_done == TOTAL_BYTES); 174 ASSERT(bytes_received_done == TOTAL_BYTES); 175 176 free(send_buffer); 177 178 MAKE_VALGRIND_HAPPY(); 179 return 0; 180 } 181