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 #if !defined(_WIN32) 23 24 #include "uv.h" 25 #include "task.h" 26 27 #include <errno.h> 28 #include <sys/socket.h> 29 #include <sys/ioctl.h> 30 #include <unistd.h> 31 #include <string.h> 32 33 static uv_tcp_t server_handle; 34 static uv_tcp_t client_handle; 35 static uv_tcp_t peer_handle; 36 static uv_poll_t poll_req[2]; 37 static uv_idle_t idle; 38 static uv_os_fd_t client_fd; 39 static uv_os_fd_t server_fd; 40 static int ticks; 41 static const int kMaxTicks = 10; 42 static int cli_pr_check = 0; 43 static int cli_rd_check = 0; 44 static int srv_rd_check = 0; 45 46 static int got_eagain(void) { 47 return errno == EAGAIN 48 || errno == EINPROGRESS 49 #ifdef EWOULDBLOCK 50 || errno == EWOULDBLOCK 51 #endif 52 ; 53 } 54 55 static void idle_cb(uv_idle_t* idle) { 56 uv_sleep(100); 57 if (++ticks < kMaxTicks) 58 return; 59 60 uv_poll_stop(&poll_req[0]); 61 uv_poll_stop(&poll_req[1]); 62 uv_close((uv_handle_t*) &server_handle, NULL); 63 uv_close((uv_handle_t*) &client_handle, NULL); 64 uv_close((uv_handle_t*) &peer_handle, NULL); 65 uv_close((uv_handle_t*) idle, NULL); 66 } 67 68 static void poll_cb(uv_poll_t* handle, int status, int events) { 69 char buffer[5]; 70 int n; 71 int fd; 72 73 ASSERT(0 == uv_fileno((uv_handle_t*)handle, &fd)); 74 memset(buffer, 0, 5); 75 76 if (events & UV_PRIORITIZED) { 77 do 78 n = recv(client_fd, &buffer, 5, MSG_OOB); 79 while (n == -1 && errno == EINTR); 80 ASSERT(n >= 0 || errno != EINVAL); 81 cli_pr_check = 1; 82 ASSERT(0 == uv_poll_stop(&poll_req[0])); 83 ASSERT(0 == uv_poll_start(&poll_req[0], 84 UV_READABLE | UV_WRITABLE, 85 poll_cb)); 86 } 87 if (events & UV_READABLE) { 88 if (fd == client_fd) { 89 do 90 n = recv(client_fd, &buffer, 5, 0); 91 while (n == -1 && errno == EINTR); 92 ASSERT(n >= 0 || errno != EINVAL); 93 if (cli_rd_check == 1) { 94 ASSERT(strncmp(buffer, "world", n) == 0); 95 ASSERT(5 == n); 96 cli_rd_check = 2; 97 } 98 if (cli_rd_check == 0) { 99 ASSERT(n == 4); 100 ASSERT(strncmp(buffer, "hello", n) == 0); 101 cli_rd_check = 1; 102 do { 103 do 104 n = recv(server_fd, &buffer, 5, 0); 105 while (n == -1 && errno == EINTR); 106 if (n > 0) { 107 ASSERT(n == 5); 108 ASSERT(strncmp(buffer, "world", n) == 0); 109 cli_rd_check = 2; 110 } 111 } while (n > 0); 112 113 ASSERT(got_eagain()); 114 } 115 } 116 if (fd == server_fd) { 117 do 118 n = recv(server_fd, &buffer, 3, 0); 119 while (n == -1 && errno == EINTR); 120 ASSERT(n >= 0 || errno != EINVAL); 121 ASSERT(3 == n); 122 ASSERT(strncmp(buffer, "foo", n) == 0); 123 srv_rd_check = 1; 124 uv_poll_stop(&poll_req[1]); 125 } 126 } 127 if (events & UV_WRITABLE) { 128 do { 129 n = send(client_fd, "foo", 3, 0); 130 } while (n < 0 && errno == EINTR); 131 ASSERT(3 == n); 132 } 133 } 134 135 static void connection_cb(uv_stream_t* handle, int status) { 136 int r; 137 138 ASSERT(0 == status); 139 ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle)); 140 ASSERT(0 == uv_fileno((uv_handle_t*) &peer_handle, &server_fd)); 141 ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[0], client_fd)); 142 ASSERT(0 == uv_poll_init_socket(uv_default_loop(), &poll_req[1], server_fd)); 143 ASSERT(0 == uv_poll_start(&poll_req[0], 144 UV_PRIORITIZED | UV_READABLE | UV_WRITABLE, 145 poll_cb)); 146 ASSERT(0 == uv_poll_start(&poll_req[1], 147 UV_READABLE, 148 poll_cb)); 149 do { 150 r = send(server_fd, "hello", 5, MSG_OOB); 151 } while (r < 0 && errno == EINTR); 152 ASSERT(5 == r); 153 154 do { 155 r = send(server_fd, "world", 5, 0); 156 } while (r < 0 && errno == EINTR); 157 ASSERT(5 == r); 158 159 ASSERT(0 == uv_idle_start(&idle, idle_cb)); 160 } 161 162 163 TEST_IMPL(poll_oob) { 164 struct sockaddr_in addr; 165 int r = 0; 166 uv_loop_t* loop; 167 168 ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); 169 loop = uv_default_loop(); 170 171 ASSERT(0 == uv_tcp_init(loop, &server_handle)); 172 ASSERT(0 == uv_tcp_init(loop, &client_handle)); 173 ASSERT(0 == uv_tcp_init(loop, &peer_handle)); 174 ASSERT(0 == uv_idle_init(loop, &idle)); 175 ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); 176 ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb)); 177 178 /* Ensure two separate packets */ 179 ASSERT(0 == uv_tcp_nodelay(&client_handle, 1)); 180 181 client_fd = socket(PF_INET, SOCK_STREAM, 0); 182 ASSERT(client_fd >= 0); 183 do { 184 errno = 0; 185 r = connect(client_fd, (const struct sockaddr*)&addr, sizeof(addr)); 186 } while (r == -1 && errno == EINTR); 187 ASSERT(r == 0); 188 189 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); 190 191 ASSERT(ticks == kMaxTicks); 192 193 /* Did client receive the POLLPRI message */ 194 ASSERT(cli_pr_check == 1); 195 /* Did client receive the POLLIN message */ 196 ASSERT(cli_rd_check == 2); 197 /* Could we write with POLLOUT and did the server receive our POLLOUT message 198 * through POLLIN. 199 */ 200 ASSERT(srv_rd_check == 1); 201 202 MAKE_VALGRIND_HAPPY(); 203 return 0; 204 } 205 206 #else 207 208 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */ 209 210 #endif 211