package com.intrbiz.bergamot.nrpe; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.ssl.SslHandler; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.WriteTimeoutHandler; import io.netty.util.concurrent.GenericFutureListener; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import com.intrbiz.bergamot.nrpe.model.NRPEPacket; import com.intrbiz.bergamot.nrpe.model.NRPEResponse; import com.intrbiz.bergamot.nrpe.netty.NRPEDecoder; import com.intrbiz.bergamot.nrpe.netty.NRPEEncoder; import com.intrbiz.bergamot.nrpe.netty.NRPEHandler; import com.intrbiz.util.IBThreadFactory; /** * A non-blocking, asynchronous NRPE client */ public class NRPEPoller { private EventLoopGroup eventLoop; private int defaultRequestTimeoutSeconds; private int defaultConnectTimeoutSeconds; public NRPEPoller(int threads, int defaultConnectTimeoutSeconds, int defaultRequestTimeoutSeconds) { this.defaultRequestTimeoutSeconds = defaultRequestTimeoutSeconds; this.defaultConnectTimeoutSeconds = defaultConnectTimeoutSeconds; // setup the Netty event loop this.eventLoop = new NioEventLoopGroup(threads, new IBThreadFactory("NRPEPoller", false)); } public NRPEPoller() { this(Runtime.getRuntime().availableProcessors(), 5, 60); } public int getDefaultRequestTimeoutSeconds() { return defaultRequestTimeoutSeconds; } public int getDefaultConnectTimeoutSeconds() { return defaultConnectTimeoutSeconds; } private SSLEngine createSSLEngine() { try { SSLEngine sslEngine = SSLContext.getDefault().createSSLEngine(); sslEngine.setEnabledCipherSuites(NRPEClient.CIPHERS); sslEngine.setEnabledProtocols(NRPEClient.PROTOCOLS); sslEngine.setUseClientMode(true); return sslEngine; } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Failed to init SSLEngine", e); } } /** * Connect to the given host and send the request packet, invoking the callback handlers * * @param host * the host of the NRPE daemon * @param port * the port of the NRPE daemon * @param request * the request packet * @param responseHandler * the response handler to invoke * @param errorHandler * the error handler to invoke should an error occur */ public void submit(String host, int port, int connectTimeout, int requestTimeout, NRPEPacket request, Consumer<NRPEPacket> responseHandler, Consumer<Throwable> errorHandler) { Bootstrap b = new Bootstrap(); b.group(this.eventLoop); b.channel(NioSocketChannel.class); b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) TimeUnit.SECONDS.toMillis(connectTimeout)); b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( new ReadTimeoutHandler(requestTimeout /* seconds */), new WriteTimeoutHandler(requestTimeout /* seconds */), new SslHandler(createSSLEngine()), new NRPEDecoder(), new NRPEEncoder(), new NRPEHandler(request, responseHandler, errorHandler) ); } }); // connect the client b.connect(host, port).addListener(new GenericFutureListener<ChannelFuture>() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isDone() && (!future.isSuccess())) { errorHandler.accept(future.cause()); } } }); } public <T> void hello(String host, T userContext, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler) throws IOException { this.hello(host, 5666, this.defaultConnectTimeoutSeconds, this.defaultRequestTimeoutSeconds, responseHandler, errorHandler); } public <T> void hello(String host, int port, int connectTimeout, int requestTimeout, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler) throws IOException { this.submit(host, port, connectTimeout, requestTimeout, new NRPEPacket().version2().hello(), (p) -> { responseHandler.accept(new NRPEResponse(p.getOutput(), p.getResponseCode(), p.getRuntime())); }, errorHandler); } public <T> void command(String host, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler, String command) throws IOException { this.command(host, 5666, this.defaultConnectTimeoutSeconds, this.defaultRequestTimeoutSeconds, responseHandler, errorHandler, command); } public <T> void command(String host, int port, int connectTimeout, int requestTimeout, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler, String command) throws IOException { this.submit(host, port, connectTimeout, requestTimeout, new NRPEPacket().version2().command(command), (p) -> {responseHandler.accept(new NRPEResponse(p.getOutput(), p.getResponseCode(), p.getRuntime()));}, errorHandler); } public <T> void command(String host, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler, String command, List<String> args) throws IOException { this.command(host, 5666, this.defaultConnectTimeoutSeconds, this.defaultRequestTimeoutSeconds, responseHandler, errorHandler, command, args); } public <T> void command(String host, int port, int connectTimeout, int requestTimeout, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler, String command, List<String> args) throws IOException { this.submit(host, port, connectTimeout, requestTimeout, new NRPEPacket().version2().command(command, args), (p) -> {responseHandler.accept(new NRPEResponse(p.getOutput(), p.getResponseCode(), p.getRuntime()));}, errorHandler); } public <T> void command(String host, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler, String command, String... args) throws IOException { this.command(host, 5666, this.defaultConnectTimeoutSeconds, this.defaultRequestTimeoutSeconds, responseHandler, errorHandler, command, args); } public <T> void command(String host, int port, int connectTimeout, int requestTimeout, Consumer<NRPEResponse> responseHandler, Consumer<Throwable> errorHandler, String command, String... args) throws IOException { this.submit(host, port, connectTimeout, requestTimeout, new NRPEPacket().version2().command(command, args), (p) -> {responseHandler.accept(new NRPEResponse(p.getOutput(), p.getResponseCode(), p.getRuntime()));}, errorHandler); } public void shutdown() { try { this.eventLoop.shutdownGracefully().await(); } catch (InterruptedException e) { } } }