/** ensure exception if we publish to multicast ipv6 address */
 public void testPublishMulticastV6() throws Exception {
   NetworkService service = new NetworkService(Settings.EMPTY);
   try {
     service.resolvePublishHostAddress("FF08::108");
     fail("should have hit exception");
   } catch (IllegalArgumentException e) {
     assertTrue(e.getMessage().contains("invalid: multicast"));
   }
 }
  /** ensure specifying wildcard ipv4 address selects reasonable publish address */
  public void testPublishAnyLocalV4() throws Exception {
    InetAddress expected = null;
    try {
      expected = NetworkUtils.getFirstNonLoopbackAddresses()[0];
    } catch (Exception e) {
      assumeNoException("test requires up-and-running non-loopback address", e);
    }

    NetworkService service = new NetworkService(Settings.EMPTY);
    assertEquals(expected, service.resolvePublishHostAddress("0.0.0.0"));
  }
  @Override
  protected void doStart() {
    this.serverOpenChannels = new OpenChannelsHandler(logger);

    if (blockingServer) {
      serverBootstrap =
          new ServerBootstrap(
              new OioServerSocketChannelFactory(
                  Executors.newCachedThreadPool(daemonThreadFactory(settings, "http_server_boss")),
                  Executors.newCachedThreadPool(
                      daemonThreadFactory(settings, "http_server_worker"))));
    } else {
      serverBootstrap =
          new ServerBootstrap(
              new NioServerSocketChannelFactory(
                  Executors.newCachedThreadPool(daemonThreadFactory(settings, "http_server_boss")),
                  Executors.newCachedThreadPool(
                      daemonThreadFactory(settings, "http_server_worker")),
                  workerCount));
    }

    serverBootstrap.setPipelineFactory(configureServerChannelPipelineFactory());

    if (!"default".equals(tcpNoDelay)) {
      serverBootstrap.setOption("child.tcpNoDelay", Booleans.parseBoolean(tcpNoDelay, null));
    }
    if (!"default".equals(tcpKeepAlive)) {
      serverBootstrap.setOption("child.keepAlive", Booleans.parseBoolean(tcpKeepAlive, null));
    }
    if (tcpSendBufferSize != null && tcpSendBufferSize.bytes() > 0) {
      serverBootstrap.setOption("child.sendBufferSize", tcpSendBufferSize.bytes());
    }
    if (tcpReceiveBufferSize != null && tcpReceiveBufferSize.bytes() > 0) {
      serverBootstrap.setOption("child.receiveBufferSize", tcpReceiveBufferSize.bytes());
    }
    serverBootstrap.setOption(
        "receiveBufferSizePredictorFactory", receiveBufferSizePredictorFactory);
    serverBootstrap.setOption(
        "child.receiveBufferSizePredictorFactory", receiveBufferSizePredictorFactory);
    serverBootstrap.setOption("reuseAddress", reuseAddress);
    serverBootstrap.setOption("child.reuseAddress", reuseAddress);

    // Bind and start to accept incoming connections.
    InetAddress hostAddresses[];
    try {
      hostAddresses = networkService.resolveBindHostAddress(bindHost);
    } catch (IOException e) {
      throw new BindHttpException("Failed to resolve host [" + bindHost + "]", e);
    }

    for (InetAddress address : hostAddresses) {
      bindAddress(address);
    }

    InetSocketAddress boundAddress = (InetSocketAddress) serverChannels.get(0).getLocalAddress();
    InetSocketAddress publishAddress;
    if (0 == publishPort) {
      publishPort = boundAddress.getPort();
    }
    try {
      publishAddress =
          new InetSocketAddress(networkService.resolvePublishHostAddress(publishHost), publishPort);
    } catch (Exception e) {
      throw new BindTransportException("Failed to resolve publish address", e);
    }
    this.boundAddress =
        new BoundTransportAddress(
            new InetSocketTransportAddress(boundAddress),
            new InetSocketTransportAddress(publishAddress));
  }
  @Override
  protected void doStart() throws ElasticsearchException {
    // Bind and start to accept incoming connections.
    InetAddress hostAddressX;
    try {
      hostAddressX = networkService.resolveBindHostAddress(bindHost);
    } catch (IOException e) {
      throw new BindHttpException("Failed to resolve host [" + bindHost + "]", e);
    }
    final InetAddress hostAddress = hostAddressX;

    InetAddress publishAddressHostX;
    try {
      publishAddressHostX = networkService.resolvePublishHostAddress(publishHost);
    } catch (IOException e) {
      throw new BindHttpException(
          "Failed to resolve publish address host [" + publishHost + "]", e);
    }
    final InetAddress publishAddressHost = publishAddressHostX;

    capiBehavior = new ElasticSearchCAPIBehavior(client, logger, bucketUUIDCache, pluginSettings);
    couchbaseBehavior =
        new ElasticSearchCouchbaseBehavior(client, logger, bucketUUIDCache, pluginSettings);

    PortsRange portsRange = new PortsRange(port);
    final AtomicReference<Exception> lastException = new AtomicReference<Exception>();
    boolean success =
        portsRange.iterate(
            new PortsRange.PortCallback() {
              @Override
              public boolean onPortNumber(int portNumber) {
                try {

                  server =
                      new CAPIServer(
                          capiBehavior,
                          couchbaseBehavior,
                          new InetSocketAddress(hostAddress, portNumber),
                          CouchbaseCAPITransportImpl.this.username,
                          CouchbaseCAPITransportImpl.this.password,
                          numVbuckets);

                  if (publishAddressHost != null) {
                    server.setPublishAddress(publishAddressHost);
                  }

                  server.start();
                } catch (Exception e) {
                  lastException.set(e);
                  return false;
                }
                return true;
              }
            });
    if (!success) {
      throw new BindHttpException("Failed to bind to [" + port + "]", lastException.get());
    }

    InetSocketAddress boundAddress = server.getBindAddress();
    InetSocketAddress publishAddress =
        new InetSocketAddress(publishAddressHost, boundAddress.getPort());
    this.boundAddress =
        new BoundTransportAddress(
            new InetSocketTransportAddress(boundAddress),
            new InetSocketTransportAddress(publishAddress));
  }
  @Override
  protected void doStart() throws ElasticsearchException {
    try {

      final String currentDir = new File(".").getCanonicalPath();
      final String tomcatDir = currentDir + File.separatorChar + "tomcat";

      logger.debug("cur dir " + currentDir);

      if (tomcat != null) {
        try {
          tomcat.stop();
          tomcat.destroy();
        } catch (final Exception e) {

        }
      }

      tomcat = new ExtendedTomcat();
      tomcat.enableNaming();
      tomcat.getServer().setPort(-1); // shutdown disabled
      tomcat.getServer().setAddress("localhost");

      final String httpProtocolImpl =
          blockingServer
              ? "org.apache.coyote.http11.Http11Protocol"
              : "org.apache.coyote.http11.Http11NioProtocol";

      final Connector httpConnector = new Connector(httpProtocolImpl);
      tomcat.setConnector(httpConnector);
      tomcat.getService().addConnector(httpConnector);

      // TODO report tomcat bug with setProtocol

      if (maxContentLength != null) {
        httpConnector.setMaxPostSize(maxContentLength.bytesAsInt());
      }

      if (maxHeaderSize != null) {
        httpConnector.setAttribute("maxHttpHeaderSize", maxHeaderSize.bytesAsInt());
      }

      if (tcpNoDelay != null) {
        httpConnector.setAttribute("tcpNoDelay", tcpNoDelay.booleanValue());
      }

      if (reuseAddress != null) {
        httpConnector.setAttribute("socket.soReuseAddress", reuseAddress.booleanValue());
      }

      if (tcpKeepAlive != null) {
        httpConnector.setAttribute("socket.soKeepAlive", tcpKeepAlive.booleanValue());
        httpConnector.setAttribute(
            "maxKeepAliveRequests", tcpKeepAlive.booleanValue() ? "100" : "1");
      }

      if (tcpReceiveBufferSize != null) {
        httpConnector.setAttribute("socket.rxBufSize", tcpReceiveBufferSize.bytesAsInt());
      }

      if (tcpSendBufferSize != null) {
        httpConnector.setAttribute("socket.txBufSize", tcpSendBufferSize.bytesAsInt());
      }

      httpConnector.setAttribute(
          "compression", compression ? String.valueOf(compressionLevel) : "off");

      if (maxChunkSize != null) {
        httpConnector.setAttribute("maxExtensionSize", maxChunkSize.bytesAsInt());
      }

      httpConnector.setPort(Integer.parseInt(port));

      tomcat.setBaseDir(tomcatDir);

      final TomcatHttpTransportHandlerServlet servlet = new TomcatHttpTransportHandlerServlet();
      servlet.setTransport(this);

      final Context ctx = tomcat.addContext("", currentDir);

      logger.debug("currentDir " + currentDir);

      Tomcat.addServlet(ctx, "ES Servlet", servlet);

      ctx.addServletMapping("/*", "ES Servlet");

      if (useSSL) {
        logger.info("Using SSL");

        // System.setProperty("javax.net.debug", "ssl");
        httpConnector.setAttribute("SSLEnabled", "true");
        httpConnector.setSecure(true);
        httpConnector.setScheme("https");

        httpConnector.setAttribute("sslProtocol", "TLS");

        httpConnector.setAttribute(
            "keystoreFile", settings.get("security.ssl.keystorefile", "keystore"));
        httpConnector.setAttribute(
            "keystorePass", settings.get("security.ssl.keystorepass", "changeit"));
        httpConnector.setAttribute(
            "keystoreType", settings.get("security.ssl.keystoretype", "JKS"));

        final String keyalias = settings.get("security.ssl.keyalias", null);

        if (keyalias != null) {
          httpConnector.setAttribute("keyAlias", keyalias);
        }

        if (useClientAuth) {

          logger.info(
              "Using SSL Client Auth (PKI), so user/roles will be retrieved from client certificate.");

          httpConnector.setAttribute("clientAuth", "true");

          httpConnector.setAttribute(
              "truststoreFile",
              settings.get("security.ssl.clientauth.truststorefile", "truststore"));
          httpConnector.setAttribute(
              "truststorePass", settings.get("security.ssl.clientauth.truststorepass", "changeit"));
          httpConnector.setAttribute(
              "truststoreType", settings.get("security.ssl.clientauth.truststoretype", "JKS"));

          /*final String loginconf = this.settings
          		.get("security.kerberos.login.conf.path");
          final String krbconf = this.settings
          		.get("security.kerberos.krb5.conf.path");

          SecurityUtil.setSystemPropertyToAbsoluteFile(
          		"java.security.auth.login.config", loginconf);
          SecurityUtil.setSystemPropertyToAbsoluteFile(
          		"java.security.krb5.conf", krbconf);*/

          // httpConnector.setAttribute("allowUnsafeLegacyRenegotiation", "true");

          final SecurityConstraint constraint = new SecurityConstraint();
          constraint.addAuthRole("*");
          constraint.setAuthConstraint(true);
          constraint.setUserConstraint("CONFIDENTIAL");

          final SecurityCollection col = new SecurityCollection();
          col.addPattern("/*");

          constraint.addCollection(col);
          ctx.addConstraint(constraint);

          final LoginConfig lc = new LoginConfig();
          lc.setAuthMethod("CLIENT-CERT");
          lc.setRealmName("clientcretificate");
          ctx.setLoginConfig(lc);

          configureJndiRealm(ctx);

          ctx.getPipeline().addValve(new SSLAuthenticator());
          logger.info("Auth Method is CLIENT-CERT");

          // http://pki-tutorial.readthedocs.org/en/latest/simple/

        }

      } else {
        if (useClientAuth) {
          logger.error("Client Auth only available with SSL");
          throw new RuntimeException("Client Auth only available with SSL");
        }

        // useClientAuth = false;
      }

      if (!useClientAuth) {
        if ("waffle".equalsIgnoreCase(kerberosMode)) {

          final Boolean testMode = settings.getAsBoolean("security.waffle.testmode", false);

          final FilterDef fd = new FilterDef();
          fd.setFilterClass("waffle.servlet.NegotiateSecurityFilter");
          fd.setFilterName("Waffle");

          if (testMode != null && testMode.booleanValue()) {

            fd.addInitParameter("principalFormat", "fqn");
            fd.addInitParameter("roleFormat", "both");
            fd.addInitParameter("allowGuestLogin", "true");
            fd.addInitParameter(
                "securityFilterProviders",
                "org.elasticsearch.plugins.security.waffle.TestProvider");

            logger.info(
                "Kerberos implementaton is WAFFLE in testmode (only work on Windows Operations system)");
          } else {
            final Map<String, String> waffleSettings =
                settings.getByPrefix("security.waffle").getAsMap();

            for (final String waffleKey : waffleSettings.keySet()) {

              fd.addInitParameter(waffleKey.substring(1), waffleSettings.get(waffleKey));

              logger.debug(waffleKey.substring(1) + "=" + waffleSettings.get(waffleKey));
            }

            fd.addInitParameter("principalFormat", "fqn");
            fd.addInitParameter("roleFormat", "both");
            fd.addInitParameter("allowGuestLogin", "false");

            logger.info(
                "Kerberos implementaton is WAFFLE (only work on Windows Operations system)");
          }

          ctx.addFilterDef(fd);
          final FilterMap fm = new FilterMap();
          fm.setFilterName("Waffle");
          fm.addURLPattern("/*");
          ctx.addFilterMap(fm);

        } else if ("spnegoad".equalsIgnoreCase(kerberosMode)) {

          // System.setProperty("sun.security.krb5.debug", "true"); // TODO
          // switch
          // off

          System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");

          final SecurityConstraint constraint = new SecurityConstraint();
          constraint.addAuthRole("*");
          constraint.setAuthConstraint(true);
          constraint.setDisplayName("spnego_sc_all");
          final SecurityCollection col = new SecurityCollection();
          col.addPattern("/*");

          constraint.addCollection(col);
          ctx.addConstraint(constraint);

          final LoginConfig lc = new LoginConfig();
          lc.setAuthMethod("SPNEGO");
          lc.setRealmName("SPNEGO");
          ctx.setLoginConfig(lc);

          logger.info("Kerberos implementaton is SPNEGOAD");

          configureJndiRealm(ctx);

          final ExtendedSpnegoAuthenticator spnegoValve = new ExtendedSpnegoAuthenticator();
          // spnegoValve.setLoginConfigName("es-login");
          spnegoValve.setStoreDelegatedCredential(true);
          ctx.getPipeline().addValve(spnegoValve);

          // final SpnegoAuthenticator spnegoValve = new SpnegoAuthenticator();
          // spnegoValve.setLoginEntryName("es-login");
          // ctx.getPipeline().addValve(spnegoValve);

        } else if ("none".equalsIgnoreCase(kerberosMode)) {

          logger.warn(
              "Kerberos is not configured so user/roles are unavailable. Host based security, in contrast, is woking. ");

        } else {
          logger.error(
              "No Kerberos implementaion '"
                  + kerberosMode
                  + "' found. Kerberos is therefore not configured so user/roles are unavailable. Host based security, in contrast, is woking. ");
        }
      }

      tomcat.start();

      logger.info("Tomcat started");

      InetSocketAddress bindAddress;
      try {
        bindAddress =
            new InetSocketAddress(
                networkService.resolveBindHostAddress(bindHost),
                tomcat.getConnector().getLocalPort());
      } catch (final Exception e) {
        throw new BindTransportException("Failed to resolve bind address", e);
      }

      InetSocketAddress publishAddress;
      try {
        publishAddress =
            new InetSocketAddress(
                networkService.resolvePublishHostAddress(publishHost), bindAddress.getPort());
      } catch (final Exception e) {
        throw new BindTransportException("Failed to resolve publish address", e);
      }

      logger.debug("bindAddress " + bindAddress);
      logger.debug("publishAddress " + publishAddress);

      boundAddress =
          new BoundTransportAddress(
              new InetSocketTransportAddress(bindAddress),
              new InetSocketTransportAddress(publishAddress));

    } catch (final Exception e) {
      throw new ElasticsearchException("Unable to start Tomcat", e);
    }
  }