use of org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel in project nifi by apache.
the class SocketChannelDispatcher method run.
@Override
public void run() {
while (!stopped) {
try {
int selected = selector.select();
// if stopped the selector could already be closed which would result in a ClosedSelectorException
if (selected > 0 && !stopped) {
Iterator<SelectionKey> selectorKeys = selector.selectedKeys().iterator();
// if stopped we don't want to modify the keys because close() may still be in progress
while (selectorKeys.hasNext() && !stopped) {
SelectionKey key = selectorKeys.next();
selectorKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isAcceptable()) {
// Handle new connections coming in
final ServerSocketChannel channel = (ServerSocketChannel) key.channel();
final SocketChannel socketChannel = channel.accept();
// Check for available connections
if (currentConnections.incrementAndGet() > maxConnections) {
currentConnections.decrementAndGet();
logger.warn("Rejecting connection from {} because max connections has been met", new Object[] { socketChannel.getRemoteAddress().toString() });
IOUtils.closeQuietly(socketChannel);
continue;
}
logger.debug("Accepted incoming connection from {}", new Object[] { socketChannel.getRemoteAddress().toString() });
// Set socket to non-blocking, and register with selector
socketChannel.configureBlocking(false);
SelectionKey readKey = socketChannel.register(selector, SelectionKey.OP_READ);
// Prepare the byte buffer for the reads, clear it out
ByteBuffer buffer = bufferPool.poll();
buffer.clear();
buffer.mark();
// If we have an SSLContext then create an SSLEngine for the channel
SSLSocketChannel sslSocketChannel = null;
if (sslContext != null) {
final SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
switch(clientAuth) {
case REQUIRED:
sslEngine.setNeedClientAuth(true);
break;
case WANT:
sslEngine.setWantClientAuth(true);
break;
case NONE:
sslEngine.setNeedClientAuth(false);
sslEngine.setWantClientAuth(false);
break;
}
sslSocketChannel = new SSLSocketChannel(sslEngine, socketChannel);
}
// Attach the buffer and SSLSocketChannel to the key
SocketChannelAttachment attachment = new SocketChannelAttachment(buffer, sslSocketChannel);
readKey.attach(attachment);
} else if (key.isReadable()) {
// Clear out the operations the select is interested in until done reading
key.interestOps(0);
// Create a handler based on the protocol and whether an SSLEngine was provided or not
final Runnable handler;
if (sslContext != null) {
handler = handlerFactory.createSSLHandler(key, this, charset, eventFactory, events, logger);
} else {
handler = handlerFactory.createHandler(key, this, charset, eventFactory, events, logger);
}
// run the handler
executor.execute(handler);
}
}
}
// Add back all idle sockets to the select
SelectionKey key;
while ((key = keyQueue.poll()) != null) {
key.interestOps(SelectionKey.OP_READ);
}
} catch (IOException e) {
logger.error("Error accepting connection from SocketChannel", e);
}
}
}
use of org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel in project nifi by apache.
the class SSLSocketChannelHandler method run.
@Override
public void run() {
boolean eof = false;
SSLSocketChannel sslSocketChannel = null;
try {
int bytesRead;
final SocketChannel socketChannel = (SocketChannel) key.channel();
final SocketChannelAttachment attachment = (SocketChannelAttachment) key.attachment();
// get the SSLSocketChannel from the attachment
sslSocketChannel = attachment.getSslSocketChannel();
// SSLSocketChannel deals with byte[] so ByteBuffer isn't used here, but we'll use the size to create a new byte[]
final ByteBuffer socketBuffer = attachment.getByteBuffer();
byte[] socketBufferArray = new byte[socketBuffer.limit()];
// read until no more data
try {
while ((bytesRead = sslSocketChannel.read(socketBufferArray)) > 0) {
processBuffer(sslSocketChannel, socketChannel, bytesRead, socketBufferArray);
logger.debug("bytes read from sslSocketChannel {}", new Object[] { bytesRead });
}
} catch (SocketTimeoutException ste) {
// SSLSocketChannel will throw this exception when 0 bytes are read and the timeout threshold
// is exceeded, we don't want to close the connection in this case
bytesRead = 0;
}
// Check for closed socket
if (bytesRead < 0) {
eof = true;
logger.debug("Reached EOF, closing connection");
} else {
logger.debug("No more data available, returning for selection");
}
} catch (ClosedByInterruptException | InterruptedException e) {
logger.debug("read loop interrupted, closing connection");
// Treat same as closed socket
eof = true;
} catch (ClosedChannelException e) {
// ClosedChannelException doesn't have a message so handle it separately from IOException
logger.error("Error reading from channel due to channel being closed", e);
// Treat same as closed socket
eof = true;
} catch (IOException e) {
logger.error("Error reading from channel due to {}", new Object[] { e.getMessage() }, e);
// Treat same as closed socket
eof = true;
} finally {
if (eof == true) {
IOUtils.closeQuietly(sslSocketChannel);
dispatcher.completeConnection(key);
} else {
dispatcher.addBackForSelection(key);
}
}
}
use of org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel in project nifi by apache.
the class SSLSocketChannelSender method open.
@Override
public void open() throws IOException {
if (sslChannel == null) {
super.open();
sslChannel = new SSLSocketChannel(sslContext, channel, true);
}
sslChannel.setTimeout(timeout);
// SSLSocketChannel will check if already connected so we can safely call this
sslChannel.connect();
sslOutputStream = new SSLSocketChannelOutputStream(sslChannel);
}
use of org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel in project nifi by apache.
the class SocketChannelRecordReaderDispatcher method run.
@Override
public void run() {
while (!stopped) {
try {
final SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel == null) {
Thread.sleep(20);
continue;
}
final SocketAddress remoteSocketAddress = socketChannel.getRemoteAddress();
socketChannel.socket().setSoTimeout(socketReadTimeout);
socketChannel.socket().setReceiveBufferSize(receiveBufferSize);
if (currentConnections.incrementAndGet() > maxConnections) {
currentConnections.decrementAndGet();
final String remoteAddress = remoteSocketAddress == null ? "null" : remoteSocketAddress.toString();
logger.warn("Rejecting connection from {} because max connections has been met", new Object[] { remoteAddress });
IOUtils.closeQuietly(socketChannel);
continue;
}
if (logger.isDebugEnabled()) {
final String remoteAddress = remoteSocketAddress == null ? "null" : remoteSocketAddress.toString();
logger.debug("Accepted connection from {}", new Object[] { remoteAddress });
}
// create a StandardSocketChannelRecordReader or an SSLSocketChannelRecordReader based on presence of SSLContext
final SocketChannelRecordReader socketChannelRecordReader;
if (sslContext == null) {
socketChannelRecordReader = new StandardSocketChannelRecordReader(socketChannel, readerFactory, this);
} else {
final SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
switch(clientAuth) {
case REQUIRED:
sslEngine.setNeedClientAuth(true);
break;
case WANT:
sslEngine.setWantClientAuth(true);
break;
case NONE:
sslEngine.setNeedClientAuth(false);
sslEngine.setWantClientAuth(false);
break;
}
final SSLSocketChannel sslSocketChannel = new SSLSocketChannel(sslEngine, socketChannel);
socketChannelRecordReader = new SSLSocketChannelRecordReader(socketChannel, sslSocketChannel, readerFactory, this);
}
// queue the SocketChannelRecordReader for processing by the processor
recordReaders.offer(socketChannelRecordReader);
} catch (Exception e) {
logger.error("Error dispatching connection: " + e.getMessage(), e);
}
}
}
use of org.apache.nifi.remote.io.socket.ssl.SSLSocketChannel 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();
}
Aggregations