@Override
  void process() throws IOException {
    try {
      final Details serverDetails = new Details(serverInetSocketAddress, localIdentifier);
      connectorBySocket.put(serverInetSocketAddress, new ServerConnector(serverDetails));

      for (InetSocketAddress client : endpoints) {
        final Details clientDetails = new Details(client, localIdentifier);
        connectorBySocket.put(client, new ClientConnector(clientDetails));
      }

      for (AbstractConnector connector : connectorBySocket.values()) {
        connector.connect();
      }

      while (selector.isOpen()) {

        registerPendingRegistrations();

        final int nSelectedKeys = selector.select(selectorTimeout);

        // its less resource intensive to set this less frequently and use an approximation
        final long approxTime = System.currentTimeMillis();

        checkThrottleInterval();

        // check that we have sent and received heartbeats
        heartBeatMonitor(approxTime);

        // set the OP_WRITE when data is ready to send
        opWriteUpdater.applyUpdates();

        if (nSelectedKeys == 0) continue; // go back and check pendingRegistrations

        final Set<SelectionKey> selectionKeys = selector.selectedKeys();
        for (final SelectionKey key : selectionKeys) {
          try {

            if (!key.isValid()) continue;

            if (key.isAcceptable()) onAccept(key);

            if (key.isConnectable()) onConnect(key);

            if (key.isReadable()) onRead(key, approxTime);

            if (key.isWritable()) onWrite(key, approxTime);

          } catch (CancelledKeyException e) {
            quietClose(key, e);
          } catch (ClosedSelectorException e) {
            quietClose(key, e);
          } catch (IOException e) {
            quietClose(key, e);
          } catch (InterruptedException e) {
            quietClose(key, e);
          } catch (Exception e) {
            LOG.info("", e);
            closeEarlyAndQuietly(key.channel());
          }
        }
        selectionKeys.clear();
      }
    } catch (CancelledKeyException e) {
      if (LOG.isDebugEnabled()) LOG.debug("", e);
    } catch (ClosedSelectorException e) {
      if (LOG.isDebugEnabled()) LOG.debug("", e);
    } catch (ClosedChannelException e) {
      if (LOG.isDebugEnabled()) LOG.debug("", e);
    } catch (ConnectException e) {
      if (LOG.isDebugEnabled()) LOG.debug("", e);
    } catch (Exception e) {
      LOG.error("", e);
    } finally {
      if (selector != null)
        try {
          selector.close();
        } catch (IOException e) {
          if (LOG.isDebugEnabled()) LOG.debug("", e);
        }
      close();
    }
  }