1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.media.audiotestharness.server.utility;
18 
19 import java.io.IOException;
20 import java.net.ServerSocket;
21 import java.util.concurrent.ThreadLocalRandom;
22 import java.util.logging.Logger;
23 
24 /** Utility Class containing utilities for IP ports. */
25 public final class PortUtility {
26     private static final Logger LOGGER = Logger.getLogger(PortUtility.class.getName());
27 
28     /** The lower bound of ports to use, currently the start of the dynamic port range */
29     public static final int START_PORT = 49152;
30 
31     /** The upper bound of ports to use, currently the end of the dynamic port range */
32     public static final int END_PORT = 65535;
33 
34     /**
35      * Maximum number of attempts that the utility should go through before failing to find an open
36      * port.
37      */
38     public static final int MAX_ATTEMPTS = 1000;
39 
PortUtility()40     private PortUtility() {}
41 
42     /**
43      * Searches for and returns the next open port number on the host system.
44      *
45      * @throws RuntimeException if unable to find an open port with {@link #MAX_ATTEMPTS} tries.
46      */
nextAvailablePort()47     public static int nextAvailablePort() {
48         int port;
49         int count = 0;
50 
51         while (count < MAX_ATTEMPTS) {
52             count++;
53             LOGGER.finest(
54                     String.format("Attempting to find open port. Number of attempts: %d", count));
55             port = ThreadLocalRandom.current().nextInt(START_PORT, END_PORT);
56             if (isPortFree(port)) {
57                 LOGGER.finest(String.format("Found open port (%d) after %d tries", port, count));
58                 return port;
59             }
60         }
61 
62         throw new RuntimeException("Unable to find an open port.");
63     }
64 
65     /**
66      * Helper method that identifies if a provided port is free.
67      *
68      * @param port the number of the port to check.
69      * @return True if the port is free, false otherwise.
70      */
isPortFree(int port)71     private static boolean isPortFree(int port) {
72 
73         // If ServerSocket throws IO Exception, port is not open.
74         try {
75             new ServerSocket(port).close();
76             return true;
77         } catch (IOException ioe) {
78             return false;
79         }
80     }
81 }
82