private LauncherServer() throws IOException {
    this.refCount = new AtomicLong(0);

    ServerSocket server = new ServerSocket();
    try {
      server.setReuseAddress(true);
      server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));

      this.clients = new ArrayList<>();
      this.threadIds = new AtomicLong();
      this.factory = new NamedThreadFactory(THREAD_NAME_FMT);
      this.pending = new ConcurrentHashMap<>();
      this.timeoutTimer = new Timer("LauncherServer-TimeoutTimer", true);
      this.server = server;
      this.running = true;

      this.serverThread =
          factory.newThread(
              new Runnable() {
                @Override
                public void run() {
                  acceptConnections();
                }
              });
      serverThread.start();
    } catch (IOException ioe) {
      close();
      throw ioe;
    } catch (Exception e) {
      close();
      throw new IOException(e);
    }
  }
 private void acceptConnections() {
   try {
     while (running) {
       final Socket client = server.accept();
       TimerTask timeout =
           new TimerTask() {
             @Override
             public void run() {
               LOG.warning("Timed out waiting for hello message from client.");
               try {
                 client.close();
               } catch (IOException ioe) {
                 // no-op.
               }
             }
           };
       ServerConnection clientConnection = new ServerConnection(client, timeout);
       Thread clientThread = factory.newThread(clientConnection);
       synchronized (timeout) {
         clientThread.start();
         synchronized (clients) {
           clients.add(clientConnection);
         }
         long timeoutMs = getConnectionTimeout();
         // 0 is used for testing to avoid issues with clock resolution / thread scheduling,
         // and force an immediate timeout.
         if (timeoutMs > 0) {
           timeoutTimer.schedule(timeout, getConnectionTimeout());
         } else {
           timeout.run();
         }
       }
     }
   } catch (IOException ioe) {
     if (running) {
       LOG.log(Level.SEVERE, "Error in accept loop.", ioe);
     }
   }
 }
 @Override
 public void close() throws IOException {
   synchronized (this) {
     if (running) {
       running = false;
       timeoutTimer.cancel();
       server.close();
       synchronized (clients) {
         List<ServerConnection> copy = new ArrayList<>(clients);
         clients.clear();
         for (ServerConnection client : copy) {
           client.close();
         }
       }
     }
   }
   if (serverThread != null) {
     try {
       serverThread.join();
     } catch (InterruptedException ie) {
       // no-op
     }
   }
 }