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 } } }