Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include <grpc/support/port_platform.h>
35 : #include "test/core/util/test_config.h"
36 : #if defined(GPR_POSIX_SOCKET) && defined(GRPC_TEST_PICK_PORT)
37 :
38 : #include "test/core/util/port.h"
39 :
40 : #include <netinet/in.h>
41 : #include <sys/socket.h>
42 : #include <stdio.h>
43 : #include <errno.h>
44 : #include <string.h>
45 : #include <unistd.h>
46 :
47 : #include <grpc/grpc.h>
48 : #include <grpc/support/alloc.h>
49 : #include <grpc/support/log.h>
50 : #include <grpc/support/string_util.h>
51 :
52 : #include "src/core/httpcli/httpcli.h"
53 : #include "src/core/support/env.h"
54 :
55 : #define NUM_RANDOM_PORTS_TO_PICK 100
56 :
57 : static int *chosen_ports = NULL;
58 : static size_t num_chosen_ports = 0;
59 :
60 0 : static int has_port_been_chosen(int port) {
61 : size_t i;
62 0 : for (i = 0; i < num_chosen_ports; i++) {
63 0 : if (chosen_ports[i] == port) {
64 0 : return 1;
65 : }
66 : }
67 0 : return 0;
68 : }
69 :
70 : typedef struct freereq {
71 : grpc_pollset pollset;
72 : int done;
73 : } freereq;
74 :
75 2902 : static void destroy_pollset_and_shutdown(grpc_exec_ctx *exec_ctx, void *p,
76 : int success) {
77 2902 : grpc_pollset_destroy(p);
78 2902 : grpc_shutdown();
79 2902 : }
80 :
81 1451 : static void freed_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
82 : const grpc_httpcli_response *response) {
83 1451 : freereq *pr = arg;
84 1451 : gpr_mu_lock(GRPC_POLLSET_MU(&pr->pollset));
85 1451 : pr->done = 1;
86 1451 : grpc_pollset_kick(&pr->pollset, NULL);
87 1451 : gpr_mu_unlock(GRPC_POLLSET_MU(&pr->pollset));
88 1451 : }
89 :
90 1451 : static void free_port_using_server(char *server, int port) {
91 : grpc_httpcli_context context;
92 : grpc_httpcli_request req;
93 : freereq pr;
94 : char *path;
95 1451 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
96 : grpc_closure shutdown_closure;
97 :
98 1451 : grpc_init();
99 :
100 1451 : memset(&pr, 0, sizeof(pr));
101 1451 : memset(&req, 0, sizeof(req));
102 1451 : grpc_pollset_init(&pr.pollset);
103 1451 : grpc_closure_init(&shutdown_closure, destroy_pollset_and_shutdown,
104 : &pr.pollset);
105 :
106 1451 : req.host = server;
107 1451 : gpr_asprintf(&path, "/drop/%d", port);
108 1451 : req.path = path;
109 :
110 1451 : grpc_httpcli_context_init(&context);
111 1451 : grpc_httpcli_get(&exec_ctx, &context, &pr.pollset, &req,
112 1451 : GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), freed_port_from_server,
113 : &pr);
114 1451 : gpr_mu_lock(GRPC_POLLSET_MU(&pr.pollset));
115 18466 : while (!pr.done) {
116 : grpc_pollset_worker worker;
117 15564 : grpc_pollset_work(&exec_ctx, &pr.pollset, &worker,
118 : gpr_now(GPR_CLOCK_MONOTONIC),
119 15564 : GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
120 : }
121 1451 : gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset));
122 :
123 1451 : grpc_httpcli_context_destroy(&context);
124 1451 : grpc_exec_ctx_finish(&exec_ctx);
125 1451 : grpc_pollset_shutdown(&exec_ctx, &pr.pollset, &shutdown_closure);
126 1451 : grpc_exec_ctx_finish(&exec_ctx);
127 1451 : gpr_free(path);
128 1451 : }
129 :
130 405 : static void free_chosen_ports() {
131 405 : char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
132 405 : if (env != NULL) {
133 : size_t i;
134 1856 : for (i = 0; i < num_chosen_ports; i++) {
135 1451 : free_port_using_server(env, chosen_ports[i]);
136 : }
137 405 : gpr_free(env);
138 : }
139 :
140 405 : gpr_free(chosen_ports);
141 405 : }
142 :
143 1451 : static void chose_port(int port) {
144 1451 : if (chosen_ports == NULL) {
145 405 : atexit(free_chosen_ports);
146 : }
147 1451 : num_chosen_ports++;
148 1451 : chosen_ports = gpr_realloc(chosen_ports, sizeof(int) * num_chosen_ports);
149 1451 : chosen_ports[num_chosen_ports - 1] = port;
150 1451 : }
151 :
152 0 : static int is_port_available(int *port, int is_tcp) {
153 0 : const int proto = is_tcp ? IPPROTO_TCP : 0;
154 0 : const int fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto);
155 0 : int one = 1;
156 : struct sockaddr_in addr;
157 0 : socklen_t alen = sizeof(addr);
158 : int actual_port;
159 :
160 0 : GPR_ASSERT(*port >= 0);
161 0 : GPR_ASSERT(*port <= 65535);
162 0 : if (fd < 0) {
163 0 : gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
164 0 : return 0;
165 : }
166 :
167 : /* Reuseaddr lets us start up a server immediately after it exits */
168 0 : if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
169 0 : gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
170 0 : close(fd);
171 0 : return 0;
172 : }
173 :
174 : /* Try binding to port */
175 0 : addr.sin_family = AF_INET;
176 0 : addr.sin_addr.s_addr = INADDR_ANY;
177 0 : addr.sin_port = htons((gpr_uint16)*port);
178 0 : if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
179 0 : gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
180 0 : close(fd);
181 0 : return 0;
182 : }
183 :
184 : /* Get the bound port number */
185 0 : if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) {
186 0 : gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
187 0 : close(fd);
188 0 : return 0;
189 : }
190 0 : GPR_ASSERT(alen <= sizeof(addr));
191 0 : actual_port = ntohs(addr.sin_port);
192 0 : GPR_ASSERT(actual_port > 0);
193 0 : if (*port == 0) {
194 0 : *port = actual_port;
195 : } else {
196 0 : GPR_ASSERT(*port == actual_port);
197 : }
198 :
199 0 : close(fd);
200 0 : return 1;
201 : }
202 :
203 : typedef struct portreq {
204 : grpc_pollset pollset;
205 : int port;
206 : int retries;
207 : char *server;
208 : grpc_httpcli_context *ctx;
209 : } portreq;
210 :
211 1451 : static void got_port_from_server(grpc_exec_ctx *exec_ctx, void *arg,
212 : const grpc_httpcli_response *response) {
213 : size_t i;
214 1451 : int port = 0;
215 1451 : portreq *pr = arg;
216 1451 : int failed = 0;
217 :
218 1451 : if (!response) {
219 0 : failed = 1;
220 0 : gpr_log(GPR_DEBUG,
221 : "failed port pick from server: retrying [response=NULL]");
222 1451 : } else if (response->status != 200) {
223 0 : failed = 1;
224 0 : gpr_log(GPR_DEBUG, "failed port pick from server: status=%d",
225 : response->status);
226 : }
227 :
228 1451 : if (failed) {
229 : grpc_httpcli_request req;
230 0 : memset(&req, 0, sizeof(req));
231 0 : GPR_ASSERT(pr->retries < 10);
232 0 : pr->retries++;
233 0 : req.host = pr->server;
234 0 : req.path = "/get";
235 0 : sleep(1);
236 0 : grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pollset, &req,
237 0 : GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
238 : pr);
239 1451 : return;
240 : }
241 1451 : GPR_ASSERT(response);
242 1451 : GPR_ASSERT(response->status == 200);
243 7255 : for (i = 0; i < response->body_length; i++) {
244 5804 : GPR_ASSERT(response->body[i] >= '0' && response->body[i] <= '9');
245 5804 : port = port * 10 + response->body[i] - '0';
246 : }
247 1451 : GPR_ASSERT(port > 1024);
248 1451 : gpr_mu_lock(GRPC_POLLSET_MU(&pr->pollset));
249 1451 : pr->port = port;
250 1451 : grpc_pollset_kick(&pr->pollset, NULL);
251 1451 : gpr_mu_unlock(GRPC_POLLSET_MU(&pr->pollset));
252 : }
253 :
254 1451 : static int pick_port_using_server(char *server) {
255 : grpc_httpcli_context context;
256 : grpc_httpcli_request req;
257 : portreq pr;
258 1451 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
259 : grpc_closure shutdown_closure;
260 :
261 1451 : grpc_init();
262 :
263 1451 : memset(&pr, 0, sizeof(pr));
264 1451 : memset(&req, 0, sizeof(req));
265 1451 : grpc_pollset_init(&pr.pollset);
266 1451 : grpc_closure_init(&shutdown_closure, destroy_pollset_and_shutdown,
267 : &pr.pollset);
268 1451 : pr.port = -1;
269 1451 : pr.server = server;
270 1451 : pr.ctx = &context;
271 :
272 1451 : req.host = server;
273 1451 : req.path = "/get";
274 :
275 1451 : grpc_httpcli_context_init(&context);
276 1451 : grpc_httpcli_get(&exec_ctx, &context, &pr.pollset, &req,
277 1451 : GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
278 : &pr);
279 1451 : grpc_exec_ctx_finish(&exec_ctx);
280 1451 : gpr_mu_lock(GRPC_POLLSET_MU(&pr.pollset));
281 18969 : while (pr.port == -1) {
282 : grpc_pollset_worker worker;
283 16067 : grpc_pollset_work(&exec_ctx, &pr.pollset, &worker,
284 : gpr_now(GPR_CLOCK_MONOTONIC),
285 16067 : GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
286 : }
287 1451 : gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset));
288 :
289 1451 : grpc_httpcli_context_destroy(&context);
290 1451 : grpc_pollset_shutdown(&exec_ctx, &pr.pollset, &shutdown_closure);
291 1451 : grpc_exec_ctx_finish(&exec_ctx);
292 :
293 1451 : return pr.port;
294 : }
295 :
296 1451 : int grpc_pick_unused_port(void) {
297 : /* We repeatedly pick a port and then see whether or not it is
298 : available for use both as a TCP socket and a UDP socket. First, we
299 : pick a random large port number. For subsequent
300 : iterations, we bind to an anonymous port and let the OS pick the
301 : port number. The random port picking reduces the probability of
302 : races with other processes on kernels that want to reuse the same
303 : port numbers over and over. */
304 :
305 : /* In alternating iterations we trial UDP ports before TCP ports UDP
306 : ports -- it could be the case that this machine has been using up
307 : UDP ports and they are scarcer. */
308 :
309 : /* Type of port to first pick in next iteration */
310 1451 : int is_tcp = 1;
311 1451 : int trial = 0;
312 :
313 1451 : char *env = gpr_getenv("GRPC_TEST_PORT_SERVER");
314 1451 : if (env) {
315 1451 : int port = pick_port_using_server(env);
316 1451 : gpr_free(env);
317 1451 : if (port != 0) {
318 1451 : chose_port(port);
319 : }
320 1451 : return port;
321 : }
322 :
323 : for (;;) {
324 : int port;
325 0 : trial++;
326 0 : if (trial == 1) {
327 0 : port = getpid() % (65536 - 30000) + 30000;
328 0 : } else if (trial <= NUM_RANDOM_PORTS_TO_PICK) {
329 0 : port = rand() % (65536 - 30000) + 30000;
330 : } else {
331 0 : port = 0;
332 : }
333 :
334 0 : if (has_port_been_chosen(port)) {
335 0 : continue;
336 : }
337 :
338 0 : if (!is_port_available(&port, is_tcp)) {
339 0 : continue;
340 : }
341 :
342 0 : GPR_ASSERT(port > 0);
343 : /* Check that the port # is free for the other type of socket also */
344 0 : if (!is_port_available(&port, !is_tcp)) {
345 : /* In the next iteration trial to bind to the other type first
346 : because perhaps it is more rare. */
347 0 : is_tcp = !is_tcp;
348 0 : continue;
349 : }
350 :
351 0 : chose_port(port);
352 0 : return port;
353 0 : }
354 :
355 : /* The port iterator reached the end without finding a suitable port. */
356 : return 0;
357 : }
358 :
359 1451 : int grpc_pick_unused_port_or_die(void) {
360 1451 : int port = grpc_pick_unused_port();
361 1451 : GPR_ASSERT(port > 0);
362 1451 : return port;
363 : }
364 :
365 : #endif /* GPR_POSIX_SOCKET && GRPC_TEST_PICK_PORT */
|