/**
   * Resolves host for REST TCP server using grid configuration.
   *
   * @param cfg Grid configuration.
   * @return REST host.
   * @throws IOException If failed to resolve REST host.
   */
  private InetAddress resolveRestTcpHost(GridConfiguration cfg) throws IOException {
    String host = cfg.getRestTcpHost();

    if (host == null) host = cfg.getLocalHost();

    return U.resolveLocalHost(host);
  }
  /**
   * Tries to start server with given parameters.
   *
   * @param hostAddr Host on which server should be bound.
   * @param port Port on which server should be bound.
   * @param lsnr Server message listener.
   * @param parser Server message parser.
   * @param sslCtx SSL context in case if SSL is enabled.
   * @param cfg Configuration for other parameters.
   * @return {@code True} if server successfully started, {@code false} if port is used and server
   *     was unable to start.
   */
  private boolean startTcpServer(
      InetAddress hostAddr,
      int port,
      GridNioServerListener<GridClientMessage> lsnr,
      GridNioParser parser,
      @Nullable SSLContext sslCtx,
      GridConfiguration cfg) {
    try {
      GridNioFilter codec = new GridNioCodecFilter(parser, log, false);

      GridNioFilter[] filters;

      if (sslCtx != null) {
        GridNioSslFilter sslFilter = new GridNioSslFilter(sslCtx, log);

        boolean auth = cfg.isRestTcpSslClientAuth();

        sslFilter.wantClientAuth(auth);

        sslFilter.needClientAuth(auth);

        filters = new GridNioFilter[] {codec, sslFilter};
      } else filters = new GridNioFilter[] {codec};

      srv =
          GridNioServer.<GridClientMessage>builder()
              .address(hostAddr)
              .port(port)
              .listener(lsnr)
              .logger(log)
              .selectorCount(cfg.getRestTcpSelectorCount())
              .gridName(ctx.gridName())
              .tcpNoDelay(cfg.isRestTcpNoDelay())
              .directBuffer(cfg.isRestTcpDirectBuffer())
              .byteOrder(ByteOrder.nativeOrder())
              .socketSendBufferSize(cfg.getRestTcpSendBufferSize())
              .socketReceiveBufferSize(cfg.getRestTcpReceiveBufferSize())
              .sendQueueLimit(cfg.getRestTcpSendQueueLimit())
              .filters(filters)
              .build();

      srv.idleTimeout(cfg.getRestIdleTimeout());

      srv.start();

      ctx.ports().registerPort(port, GridPortProtocol.TCP, getClass());

      return true;
    } catch (GridException e) {
      if (log.isDebugEnabled())
        log.debug(
            "Failed to start " + name() + " protocol on port " + port + ": " + e.getMessage());

      return false;
    }
  }
  /** {@inheritDoc} */
  @SuppressWarnings("BusyWait")
  @Override
  public void start(final GridRestProtocolHandler hnd) throws GridException {
    assert hnd != null;

    GridConfiguration cfg = ctx.config();

    GridNioServerListener<GridClientMessage> lsnr = new GridTcpRestNioListener(log, hnd);

    GridNioParser parser = new GridTcpRestParser(log);

    try {
      host = resolveRestTcpHost(cfg);

      SSLContext sslCtx = null;

      if (cfg.isRestTcpSslEnabled()) {
        GridSslContextFactory factory = cfg.getRestTcpSslContextFactory();

        if (factory == null)
          // Thrown SSL exception instead of GridException for writing correct warning message into
          // log.
          throw new SSLException("SSL is enabled, but SSL context factory is not specified.");

        sslCtx = factory.createSslContext();
      }

      int lastPort = cfg.getRestTcpPort() + cfg.getRestPortRange() - 1;

      for (port = cfg.getRestTcpPort(); port <= lastPort; port++) {
        if (startTcpServer(host, port, lsnr, parser, sslCtx, cfg)) {
          if (log.isInfoEnabled()) log.info(startInfo());

          return;
        }
      }

      U.warn(
          log,
          "Failed to start TCP binary REST server (possibly all ports in range are in use) "
              + "[firstPort="
              + cfg.getRestTcpPort()
              + ", lastPort="
              + lastPort
              + ", host="
              + host
              + ']');
    } catch (SSLException e) {
      U.warn(
          log,
          "Failed to start " + name() + " protocol on port " + port + ": " + e.getMessage(),
          "Failed to start "
              + name()
              + " protocol on port "
              + port
              + ". Check if SSL context factory is "
              + "properly configured.");
    } catch (IOException e) {
      U.warn(
          log,
          "Failed to start " + name() + " protocol on port " + port + ": " + e.getMessage(),
          "Failed to start "
              + name()
              + " protocol on port "
              + port
              + ". "
              + "Check restTcpHost configuration property.");
    }
  }