Search in sources :

Example 1 with ServerProtocol

use of org.apache.nifi.remote.protocol.ServerProtocol in project nifi by apache.

the class SocketRemoteSiteListener method start.

@Override
public void start() throws IOException {
    final boolean secure = (sslContext != null);
    final List<Thread> threads = new ArrayList<Thread>();
    final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.configureBlocking(true);
    serverSocketChannel.bind(new InetSocketAddress(socketPort));
    stopped.set(false);
    final Thread listenerThread = new Thread(new Runnable() {

        private int threadCount = 0;

        @Override
        public void run() {
            while (!stopped.get()) {
                final ProcessGroup processGroup = rootGroup.get();
                // the processGroup.
                if ((nodeInformant == null) && (processGroup == null || (processGroup.getInputPorts().isEmpty() && processGroup.getOutputPorts().isEmpty()))) {
                    try {
                        Thread.sleep(2000L);
                    } catch (final Exception e) {
                    }
                    continue;
                }
                LOG.trace("Accepting Connection...");
                Socket acceptedSocket = null;
                try {
                    serverSocketChannel.configureBlocking(false);
                    final ServerSocket serverSocket = serverSocketChannel.socket();
                    serverSocket.setSoTimeout(2000);
                    while (!stopped.get() && acceptedSocket == null) {
                        try {
                            acceptedSocket = serverSocket.accept();
                        } catch (final SocketTimeoutException ste) {
                            continue;
                        }
                    }
                } catch (final IOException e) {
                    LOG.error("RemoteSiteListener Unable to accept connection due to {}", e.toString());
                    if (LOG.isDebugEnabled()) {
                        LOG.error("", e);
                    }
                    continue;
                }
                LOG.trace("Got connection");
                if (stopped.get()) {
                    break;
                }
                final Socket socket = acceptedSocket;
                final SocketChannel socketChannel = socket.getChannel();
                final Thread thread = new Thread(new Runnable() {

                    @Override
                    public void run() {
                        LOG.debug("{} Determining URL of connection", this);
                        final InetAddress inetAddress = socket.getInetAddress();
                        String clientHostName = inetAddress.getHostName();
                        final int slashIndex = clientHostName.indexOf("/");
                        if (slashIndex == 0) {
                            clientHostName = clientHostName.substring(1);
                        } else if (slashIndex > 0) {
                            clientHostName = clientHostName.substring(0, slashIndex);
                        }
                        final int clientPort = socket.getPort();
                        final String peerUri = "nifi://" + clientHostName + ":" + clientPort;
                        LOG.debug("{} Connection URL is {}", this, peerUri);
                        final CommunicationsSession commsSession;
                        final String dn;
                        try {
                            if (secure) {
                                final SSLSocketChannel sslSocketChannel = new SSLSocketChannel(sslContext, socketChannel, false);
                                LOG.trace("Channel is secure; connecting...");
                                sslSocketChannel.connect();
                                LOG.trace("Channel connected");
                                commsSession = new SSLSocketChannelCommunicationsSession(sslSocketChannel);
                                dn = sslSocketChannel.getDn();
                                commsSession.setUserDn(dn);
                            } else {
                                LOG.trace("{} Channel is not secure", this);
                                commsSession = new SocketChannelCommunicationsSession(socketChannel);
                                dn = null;
                            }
                        } catch (final Exception e) {
                            LOG.error("RemoteSiteListener Unable to accept connection from {} due to {}", socket, e.toString());
                            if (LOG.isDebugEnabled()) {
                                LOG.error("", e);
                            }
                            try {
                                socketChannel.close();
                            } catch (IOException swallow) {
                            }
                            return;
                        }
                        LOG.info("Received connection from {}, User DN: {}", socket.getInetAddress(), dn);
                        final InputStream socketIn;
                        final OutputStream socketOut;
                        try {
                            socketIn = commsSession.getInput().getInputStream();
                            socketOut = commsSession.getOutput().getOutputStream();
                        } catch (final IOException e) {
                            LOG.error("Connection dropped from {} before any data was transmitted", peerUri);
                            try {
                                commsSession.close();
                            } catch (final IOException ioe) {
                            }
                            return;
                        }
                        final DataInputStream dis = new DataInputStream(socketIn);
                        final DataOutputStream dos = new DataOutputStream(socketOut);
                        ServerProtocol protocol = null;
                        Peer peer = null;
                        try {
                            // ensure that we are communicating with another NiFi
                            LOG.debug("Verifying magic bytes...");
                            verifyMagicBytes(dis, peerUri);
                            LOG.debug("Receiving Server Protocol Negotiation");
                            protocol = RemoteResourceFactory.receiveServerProtocolNegotiation(dis, dos);
                            protocol.setRootProcessGroup(rootGroup.get());
                            protocol.setNodeInformant(nodeInformant);
                            final PeerDescription description = new PeerDescription(clientHostName, clientPort, sslContext != null);
                            peer = new Peer(description, commsSession, peerUri, "nifi://localhost:" + getPort());
                            LOG.debug("Handshaking....");
                            protocol.handshake(peer);
                            if (!protocol.isHandshakeSuccessful()) {
                                LOG.error("Handshake failed with {}; closing connection", peer);
                                try {
                                    peer.close();
                                } catch (final IOException e) {
                                    LOG.warn("Failed to close {} due to {}", peer, e);
                                }
                                // no need to shutdown protocol because we failed to perform handshake
                                return;
                            }
                            commsSession.setTimeout((int) protocol.getRequestExpiration());
                            LOG.info("Successfully negotiated ServerProtocol {} Version {} with {}", new Object[] { protocol.getResourceName(), protocol.getVersionNegotiator().getVersion(), peer });
                            try {
                                while (!protocol.isShutdown()) {
                                    LOG.trace("Getting Protocol Request Type...");
                                    int timeoutCount = 0;
                                    RequestType requestType = null;
                                    while (requestType == null) {
                                        try {
                                            requestType = protocol.getRequestType(peer);
                                        } catch (final SocketTimeoutException e) {
                                            // Give the timeout a bit longer (twice as long) to receive the Request Type,
                                            // in order to attempt to receive more data without shutting down the socket if we don't
                                            // have to.
                                            LOG.debug("{} Timed out waiting to receive RequestType using {} with {}", new Object[] { this, protocol, peer });
                                            timeoutCount++;
                                            requestType = null;
                                            if (timeoutCount >= 2) {
                                                throw e;
                                            }
                                        }
                                    }
                                    handleRequest(protocol, peer, requestType);
                                }
                                LOG.debug("Finished communicating with {} ({})", peer, protocol);
                            } catch (final Exception e) {
                                LOG.error("Unable to communicate with remote instance {} ({}) due to {}; closing connection", peer, protocol, e.toString());
                                if (LOG.isDebugEnabled()) {
                                    LOG.error("", e);
                                }
                            }
                        } catch (final IOException e) {
                            LOG.error("Unable to communicate with remote instance {} due to {}; closing connection", peer, e.toString());
                            if (LOG.isDebugEnabled()) {
                                LOG.error("", e);
                            }
                        } catch (final Throwable t) {
                            LOG.error("Handshake failed when communicating with {}; closing connection. Reason for failure: {}", peerUri, t.toString());
                            if (LOG.isDebugEnabled()) {
                                LOG.error("", t);
                            }
                        } finally {
                            LOG.trace("Cleaning up");
                            try {
                                if (protocol != null && peer != null) {
                                    protocol.shutdown(peer);
                                }
                            } catch (final Exception protocolException) {
                                LOG.warn("Failed to shutdown protocol due to {}", protocolException.toString());
                            }
                            try {
                                if (peer != null) {
                                    peer.close();
                                }
                            } catch (final Exception peerException) {
                                LOG.warn("Failed to close peer due to {}; some resources may not be appropriately cleaned up", peerException.toString());
                            }
                            LOG.trace("Finished cleaning up");
                        }
                    }
                });
                thread.setName("Site-to-Site Worker Thread-" + (threadCount++));
                LOG.debug("Handing connection to {}", thread);
                thread.start();
                threads.add(thread);
                threads.removeIf(t -> !t.isAlive());
            }
            for (Thread thread : threads) {
                if (thread != null) {
                    thread.interrupt();
                }
            }
        }
    });
    listenerThread.setName("Site-to-Site Listener");
    listenerThread.start();
}
Also used : DataInputStream(java.io.DataInputStream) SSLContext(javax.net.ssl.SSLContext) Socket(java.net.Socket) Arrays(java.util.Arrays) ProcessGroup(org.apache.nifi.groups.ProcessGroup) BadRequestException(org.apache.nifi.remote.exception.BadRequestException) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) NodeInformant(org.apache.nifi.remote.cluster.NodeInformant) NotAuthorizedException(org.apache.nifi.remote.exception.NotAuthorizedException) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayList(java.util.ArrayList) InetAddress(java.net.InetAddress) ServerSocket(java.net.ServerSocket) HandshakeException(org.apache.nifi.remote.exception.HandshakeException) SocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.SocketChannelCommunicationsSession) DataOutputStream(java.io.DataOutputStream) SocketChannel(java.nio.channels.SocketChannel) SocketTimeoutException(java.net.SocketTimeoutException) ServerProtocol(org.apache.nifi.remote.protocol.ServerProtocol) CommunicationsSession(org.apache.nifi.remote.protocol.CommunicationsSession) OutputStream(java.io.OutputStream) RequestType(org.apache.nifi.remote.protocol.RequestType) NodeInformation(org.apache.nifi.remote.cluster.NodeInformation) Logger(org.slf4j.Logger) SSLSocketChannel(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel) IOException(java.io.IOException) SSLSocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannelCommunicationsSession) EOFException(java.io.EOFException) InetSocketAddress(java.net.InetSocketAddress) ServerSocketChannel(java.nio.channels.ServerSocketChannel) List(java.util.List) NiFiProperties(org.apache.nifi.util.NiFiProperties) RequestExpiredException(org.apache.nifi.remote.exception.RequestExpiredException) Optional(java.util.Optional) ClusterNodeInformation(org.apache.nifi.remote.cluster.ClusterNodeInformation) InputStream(java.io.InputStream) SocketChannel(java.nio.channels.SocketChannel) SSLSocketChannel(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel) ServerSocketChannel(java.nio.channels.ServerSocketChannel) SSLSocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannelCommunicationsSession) InetSocketAddress(java.net.InetSocketAddress) DataOutputStream(java.io.DataOutputStream) DataOutputStream(java.io.DataOutputStream) OutputStream(java.io.OutputStream) ArrayList(java.util.ArrayList) SocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.SocketChannelCommunicationsSession) CommunicationsSession(org.apache.nifi.remote.protocol.CommunicationsSession) SSLSocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannelCommunicationsSession) ServerSocketChannel(java.nio.channels.ServerSocketChannel) DataInputStream(java.io.DataInputStream) InputStream(java.io.InputStream) ServerSocket(java.net.ServerSocket) IOException(java.io.IOException) DataInputStream(java.io.DataInputStream) ServerProtocol(org.apache.nifi.remote.protocol.ServerProtocol) BadRequestException(org.apache.nifi.remote.exception.BadRequestException) NotAuthorizedException(org.apache.nifi.remote.exception.NotAuthorizedException) HandshakeException(org.apache.nifi.remote.exception.HandshakeException) SocketTimeoutException(java.net.SocketTimeoutException) IOException(java.io.IOException) EOFException(java.io.EOFException) RequestExpiredException(org.apache.nifi.remote.exception.RequestExpiredException) SocketTimeoutException(java.net.SocketTimeoutException) SSLSocketChannel(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel) ProcessGroup(org.apache.nifi.groups.ProcessGroup) SocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.SocketChannelCommunicationsSession) SSLSocketChannelCommunicationsSession(org.apache.nifi.remote.io.socket.ssl.SSLSocketChannelCommunicationsSession) InetAddress(java.net.InetAddress) Socket(java.net.Socket) ServerSocket(java.net.ServerSocket) RequestType(org.apache.nifi.remote.protocol.RequestType)

Example 2 with ServerProtocol

use of org.apache.nifi.remote.protocol.ServerProtocol in project nifi by apache.

the class StandardRootGroupPort method onTrigger.

private void onTrigger(final ProcessContext context, final ProcessSession session, final FlowFileRequest flowFileRequest) {
    final ServerProtocol protocol = flowFileRequest.getProtocol();
    final BlockingQueue<ProcessingResult> responseQueue = flowFileRequest.getResponseQueue();
    if (flowFileRequest.isExpired()) {
        final String message = String.format("%s Cannot service request from %s because the request has timed out", this, flowFileRequest.getPeer());
        logger.warn(message);
        eventReporter.reportEvent(Severity.WARNING, CATEGORY, message);
        responseQueue.add(new ProcessingResult(new RequestExpiredException()));
        return;
    }
    final Peer peer = flowFileRequest.getPeer();
    final CommunicationsSession commsSession = peer.getCommunicationsSession();
    final String sourceDn = commsSession.getUserDn();
    logger.debug("{} Servicing request for {} (DN={})", this, peer, sourceDn);
    final PortAuthorizationResult authorizationResult = checkUserAuthorization(sourceDn);
    if (!authorizationResult.isAuthorized()) {
        final String message = String.format("%s Cannot service request from %s (DN=%s) because peer is not authorized to communicate with this port: %s", this, flowFileRequest.getPeer(), flowFileRequest.getPeer().getCommunicationsSession().getUserDn(), authorizationResult.getExplanation());
        logger.error(message);
        eventReporter.reportEvent(Severity.ERROR, CATEGORY, message);
        responseQueue.add(new ProcessingResult(new NotAuthorizedException(authorizationResult.getExplanation())));
        return;
    }
    final FlowFileCodec codec = protocol.getPreNegotiatedCodec();
    if (codec == null) {
        responseQueue.add(new ProcessingResult(new BadRequestException("None of the supported FlowFile Codecs supplied is compatible with this instance")));
        return;
    }
    final int transferCount;
    try {
        if (getConnectableType() == ConnectableType.INPUT_PORT) {
            transferCount = receiveFlowFiles(context, session, codec, flowFileRequest);
        } else {
            transferCount = transferFlowFiles(context, session, codec, flowFileRequest);
        }
    } catch (final IOException e) {
        session.rollback();
        responseQueue.add(new ProcessingResult(e));
        return;
    } catch (final Exception e) {
        session.rollback();
        responseQueue.add(new ProcessingResult(e));
        return;
    }
    // TODO: Comfirm this. Session.commit here is not required since it has been committed inside receiveFlowFiles/transferFlowFiles.
    // session.commit();
    responseQueue.add(new ProcessingResult(transferCount));
}
Also used : RequestExpiredException(org.apache.nifi.remote.exception.RequestExpiredException) CommunicationsSession(org.apache.nifi.remote.protocol.CommunicationsSession) NotAuthorizedException(org.apache.nifi.remote.exception.NotAuthorizedException) IOException(java.io.IOException) ServerProtocol(org.apache.nifi.remote.protocol.ServerProtocol) FlowFileCodec(org.apache.nifi.remote.codec.FlowFileCodec) BadRequestException(org.apache.nifi.remote.exception.BadRequestException) ProtocolException(org.apache.nifi.remote.exception.ProtocolException) TransmissionDisabledException(org.apache.nifi.remote.exception.TransmissionDisabledException) NotAuthorizedException(org.apache.nifi.remote.exception.NotAuthorizedException) ProcessException(org.apache.nifi.processor.exception.ProcessException) SocketTimeoutException(java.net.SocketTimeoutException) IOException(java.io.IOException) RequestExpiredException(org.apache.nifi.remote.exception.RequestExpiredException) BadRequestException(org.apache.nifi.remote.exception.BadRequestException)

Example 3 with ServerProtocol

use of org.apache.nifi.remote.protocol.ServerProtocol in project nifi by apache.

the class TestSocketRemoteSiteListener method testRequestPeerList.

@Test
public void testRequestPeerList() throws Exception {
    Method method = SocketRemoteSiteListener.class.getDeclaredMethod("handleRequest", ServerProtocol.class, Peer.class, RequestType.class);
    method.setAccessible(true);
    final NiFiProperties nifiProperties = spy(NiFiProperties.class);
    final int apiPort = 8080;
    final int remoteSocketPort = 8081;
    final String remoteInputHost = "node1.example.com";
    when(nifiProperties.getPort()).thenReturn(apiPort);
    when(nifiProperties.getRemoteInputHost()).thenReturn(remoteInputHost);
    when(nifiProperties.getRemoteInputPort()).thenReturn(remoteSocketPort);
    // Even if HTTP transport is disabled, RAW should work.
    when(nifiProperties.getRemoteInputHttpPort()).thenReturn(null);
    when(nifiProperties.isSiteToSiteHttpEnabled()).thenReturn(false);
    when(nifiProperties.isSiteToSiteSecure()).thenReturn(false);
    final SocketRemoteSiteListener listener = new SocketRemoteSiteListener(remoteSocketPort, null, nifiProperties);
    final ServerProtocol serverProtocol = mock(ServerProtocol.class);
    doAnswer(invocation -> {
        final NodeInformation self = invocation.getArgumentAt(2, NodeInformation.class);
        // Listener should inform about itself properly:
        assertEquals(remoteInputHost, self.getSiteToSiteHostname());
        assertEquals(remoteSocketPort, self.getSiteToSitePort().intValue());
        assertNull(self.getSiteToSiteHttpApiPort());
        assertEquals(apiPort, self.getAPIPort());
        return null;
    }).when(serverProtocol).sendPeerList(any(Peer.class), any(Optional.class), any(NodeInformation.class));
    final Peer peer = null;
    method.invoke(listener, serverProtocol, peer, RequestType.REQUEST_PEER_LIST);
}
Also used : NiFiProperties(org.apache.nifi.util.NiFiProperties) NodeInformation(org.apache.nifi.remote.cluster.NodeInformation) Optional(java.util.Optional) Method(java.lang.reflect.Method) ServerProtocol(org.apache.nifi.remote.protocol.ServerProtocol) Test(org.junit.Test)

Aggregations

ServerProtocol (org.apache.nifi.remote.protocol.ServerProtocol)3 IOException (java.io.IOException)2 SocketTimeoutException (java.net.SocketTimeoutException)2 Optional (java.util.Optional)2 NodeInformation (org.apache.nifi.remote.cluster.NodeInformation)2 BadRequestException (org.apache.nifi.remote.exception.BadRequestException)2 NotAuthorizedException (org.apache.nifi.remote.exception.NotAuthorizedException)2 RequestExpiredException (org.apache.nifi.remote.exception.RequestExpiredException)2 CommunicationsSession (org.apache.nifi.remote.protocol.CommunicationsSession)2 NiFiProperties (org.apache.nifi.util.NiFiProperties)2 DataInputStream (java.io.DataInputStream)1 DataOutputStream (java.io.DataOutputStream)1 EOFException (java.io.EOFException)1 InputStream (java.io.InputStream)1 OutputStream (java.io.OutputStream)1 Method (java.lang.reflect.Method)1 InetAddress (java.net.InetAddress)1 InetSocketAddress (java.net.InetSocketAddress)1 ServerSocket (java.net.ServerSocket)1 Socket (java.net.Socket)1