I am trying to integrate some two code bases. One code base uses blocking I/O. The other code base uses non-blocking I/O.
The hook where I can integrate the two of these is a plain old-fashioned acceptor thread.
This acceptor thread reads the sub-protocol information from the socket and then based on the sub-protocol name forwards to the corresponding handler.
The other side of the code has it's own selector thread but only exposes a higher level set of constructs.
So basically I need to - in the acceptor thread's spawned worker thread - fire up the SSLEngine validate some sub-protocol information and then hand the whole thing off to the other code base's selector thread.
To make things more complicated, there is a fall-back path on the second code base whereby if it gets a Socket that was not opened with a SocketChannel it will drop down to blocking mode... and this is the bit that is causing me issues...
Namely it is not safe for me to assume that Socket.getChannel()!=null
So my SSLEngine code needs to take account of that possibility and set up the SSLEngine without using the non-blocking I/O APIs...
So far, I keep hitting blocking read calls that stall the engine...
Question does anyone know of any examples where SSLEngine has been used with a traditional InputStream/OutputStream rather than with a SocketChannel
Yes for handshake.
It is sad that we can't use SSLSocket.getSession for SSLEngine.
But we cat use SSLEngine in blocking mode.
See jdk1.8.0_112/sample/nio/server/ChannelIOSecure.java
Blocking:
method1(){
....
socketChannel.configureBlocking(true);
SSLEngine engine = sslContext.createSSLEngine();
engine.setUseClientMode(false);//server
engine.setNeedClientAuth(true);
this.outNetBB = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
outNetBB.position(0);
outNetBB.limit(0);
this.inNetBB = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
this.requestBB = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
this.hsBB = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
initialHSComplete = false;
while(initialHSComplete != true)
doHandshake(socketChannel, engine, null);
}
private boolean tryFlush(ByteBuffer bb, SocketChannel socketChannel) throws IOException {
socketChannel.write(bb);
return !bb.hasRemaining();
}
private SSLEngineResult.HandshakeStatus doTasks(SSLEngine sslEngine) {
Runnable runnable;
/*
* We could run this in a separate thread, but
* do in the current for now.
*/
while ((runnable = sslEngine.getDelegatedTask()) != null) {
runnable.run();
}
return sslEngine.getHandshakeStatus();
}
private ByteBuffer outNetBB;
int netBBSize;
private ByteBuffer inNetBB;
int appBBSize;
private ByteBuffer requestBB;
private ByteBuffer hsBB;
private boolean initialHSComplete; // Handshake complete status
HandshakeStatus initialHSStatus = HandshakeStatus.NEED_UNWRAP; //server
private boolean doHandshake(SocketChannel sc, SSLEngine sslEngine, SelectionKey sk) throws IOException {
SSLEngineResult result;
if (initialHSComplete) {
return initialHSComplete;
}
/*
* Flush out the outgoing buffer, if there's anything left in
* it.
*/
if (outNetBB.hasRemaining()) {
System.out.println("doha wtf");
if (!tryFlush(outNetBB, sc)) {
return false;
}
// See if we need to switch from write to read mode.
switch (initialHSStatus) {
// Is this the last buffer?
case FINISHED:
initialHSComplete = true;
// Fall-through to reregister need for a Read.
case NEED_UNWRAP:
if (sk != null) {
sk.interestOps(SelectionKey.OP_READ);
}
break;
}
return initialHSComplete;
}
switch (initialHSStatus) {
case NEED_UNWRAP:
System.out.println("before read");
if (sc.read(inNetBB) == -1) {
sslEngine.closeInbound();
return initialHSComplete;
}
System.out.println("after read");
needIO:
while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) {
System.out.println("initialHSStatus"+initialHSStatus);
resizeRequestBB(); // expected room for unwrap
inNetBB.flip();
result = sslEngine.unwrap(inNetBB, requestBB);
inNetBB.compact();
System.out.println("result"+result);
initialHSStatus = result.getHandshakeStatus();
switch (result.getStatus()) {
case OK:
switch (initialHSStatus) {
case NOT_HANDSHAKING:
throw new IOException(
"Not handshaking during initial handshake");
case NEED_TASK:
initialHSStatus = doTasks(sslEngine);
break;
case FINISHED:
initialHSComplete = true;
break needIO;
}
break;
case BUFFER_UNDERFLOW:
// Resize buffer if needed.
netBBSize = sslEngine.getSession().getPacketBufferSize();
if (netBBSize > inNetBB.capacity()) {
resizeResponseBB();
}
/*
* Need to go reread the Channel for more data.
*/
if (sk != null) {
sk.interestOps(SelectionKey.OP_READ);
}
break needIO;
case BUFFER_OVERFLOW:
// Reset the application buffer size.
appBBSize =
sslEngine.getSession().getApplicationBufferSize();
break;
default: //CLOSED:
throw new IOException("Received" + result.getStatus() +
"during initial handshaking");
}
System.out.println("bottom of needIO");
} // "needIO" block.
System.out.println("after needIO "+initialHSStatus);
/*
* Just transitioned from read to write.
*/
if (initialHSStatus != HandshakeStatus.NEED_WRAP) {
break;
}
// Fall through and fill the write buffers.
case NEED_WRAP:
/*
* The flush above guarantees the out buffer to be empty
*/
outNetBB.clear();
result = sslEngine.wrap(hsBB, outNetBB);
outNetBB.flip();
initialHSStatus = result.getHandshakeStatus();
System.out.println("result wrap="+result);
switch (result.getStatus()) {
case OK:
if (initialHSStatus == HandshakeStatus.NEED_TASK) {
initialHSStatus = doTasks(sslEngine);
}
System.out.println("here");
if (sk != null) {
sk.interestOps(SelectionKey.OP_WRITE);
}
System.out.println("here2");
break;
default: // BUFFER_OVERFLOW/BUFFER_UNDERFLOW/CLOSED:
throw new IOException("Received" + result.getStatus() +
"during initial handshaking");
}
break;
default: // NOT_HANDSHAKING/NEED_TASK/FINISHED
throw new RuntimeException("Invalid Handshaking State" +
initialHSStatus);
} // switch
return initialHSComplete;
}
/*private void tryFlush(SocketChannel sc) throws IOException {
System.out.println("flush"+outNetBB);
sc.write(outNetBB);
if (!outNetBB.hasRemaining())
outNetBB.clear();
}*/
//}
//}
private void resizeResponseBB() {
ByteBuffer bb = ByteBuffer.allocate(netBBSize);
inNetBB.flip();
bb.put(inNetBB);
inNetBB = bb;
}
protected void resizeRequestBB() {
int remaining = appBBSize;
if (requestBB.remaining() < remaining) {
// Expand buffer for large request
ByteBuffer bb = ByteBuffer.allocate(requestBB.capacity() * 2);
requestBB.flip();
bb.put(requestBB);
requestBB = bb;
}
}
To change to non-blocking add:
socketChannel.configureBlocking(true);
Selector selector = Selector.open();
SelectionKey sk = socketChannel.register(selector, SelectionKey.OP_READ);
while(initialHSComplete != true){
selector.select();
doHandshake(socketChannel, engine, sk);
Related
I'm currently trying to create an App which enables me to control an Arduino board. For some reason, whenever it gets to the stage where the server waits for a message and gets to this loop, the loop breaks without any exceptions thrown when there is no action taken.
What I mean is that if I don't use any buttons to control the board, the loop breaks.
for(;;) {
if(message.equals("END")) {
break;
}
message = "";
switch (arduinoState) {
case 1: sendMessage("Server[Cmd]: fwd");
arduinoState = 0;
break;
case 2: sendMessage("Server[Cmd]: right");
arduinoState = 0;
break;
case 3: sendMessage("Server[Cmd]: bwd");
arduinoState = 0;
break;
case 4: sendMessage("Server[Cmd]: left");
arduinoState = 0;
break;
case 5: sendMessage("Server[Cmd]: kante");
arduinoState = 0;
break;
}
message = input.readLine();
updateStatusHandler.post(new updateStatusThread("Arduino: " + message, false));
}
EDIT: As requested once, here is the Server class.
So I've found a solution. The problem was that message = input.readLine(); keeps reading lines till the stream ends. As arduinoState = 0, no message will be sent to the client as there's no action to do thus no message from the client will be returned. This ends to a continously loop of reading. This means that even if I would change arduinoState, nothing will happen.
Solution: What I did was creating a class which is treated like a thread. Message will now on be sent independently from the waitForConnection() method.
sendMessageThread are used in setOnClickListeners() for buttons I use in the app.
class sendMessageThread implements Runnable {
private String s = "";
public sendMessageThread(String s) {
this.s = s;
}
public void run() {
try {
mWriter.write(s + '\n');
mWriter.flush();
mHandler.post(new updateStatusThread("Befehl gesendet: \"" + s + "\"", false));
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I had to do a workaround lowering StrictMode. Why? Although I'm using a thread to take network actions, the exception android.os.NetworkOnMainThreadException is thrown. I guess it's because I'm using mWriter (BufferedWriter) as a global reference. I fetch the BufferedWriter in whileConnected() in the Server class.
StrictMode workaround:
//Remember to set it in the onCreate() method,
//right after super.onCreate() and setContentView()
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
whileConnected() method
private void whileConnected() {
try {
mWriter = this.output;
do {
input.ready();
String line;
while((line = input.readLine()) != null) {
if(line.length() > 0) {
mHandler.post(new updateStatusThread("Arduino: " + line, false));
break;
}
}
} while (!message.equals("END"));
} catch (Exception e) {
e.printStackTrace();
}
}
If you still have any questions or tips and tricks to improve myself, feel free to leave an answer or comment down below.
Maybe the issue is infinite looping on UI thread, it's just a guess.
Also, have you tried while loop?
My sender is sending 10000 requests per second (or even more) but my ServerSocketChannel is only able to read and process (in thread) 8000 requests (~appx).
Dummy code is like this:
public class NioReceiver {
private int port = -1;
private static String message = null;
public void receive() throws IOException {
// Get the selector
Selector selector = Selector.open();
// Selector is open for making connection
// Get the server socket channel and register using selector
ServerSocketChannel SS = ServerSocketChannel.open();
InetSocketAddress hostAddress = new InetSocketAddress(this.port);
SS.bind(hostAddress);
SS.configureBlocking(false);
int ops = SS.validOps();
SelectionKey selectKy = SS.register(selector, ops, null);
for (;;) {
//Waiting for the select operation...
int noOfKeys = selector.select();
// The Number of selected keys are: noOfKeys
Set selectedKeys = selector.selectedKeys();
Iterator itr = selectedKeys.iterator();
while (itr.hasNext()) {
ByteBuffer buffer = ByteBuffer.allocate(1024 * 60);
SelectionKey ky = (SelectionKey) itr.next();
if (ky.isAcceptable()) {
// The new client connection is accepted
SocketChannel client = SS.accept();
client.configureBlocking(false);
// The new connection is added to a selector
client.register(selector, SelectionKey.OP_READ);
// The new connection is accepted from the client: client
} else if (ky.isReadable()) {
// Data is read from the client
SocketChannel client = (SocketChannel) ky.channel();
String output = null;
buffer.clear();
int charRead = -1;
try {
charRead = client.read(buffer);
} catch (IOException e) {
continue;
}
if (charRead <= 0) {
// client closed
client.close();
} else {
output = new String(buffer.array());
message = output;
try {
new Thread(() -> {
processAndStore(message);
}).start();
} catch (Exception e) {
System.err.println("Thread exception:::" + e.getMessage());
}
} // else if of client.isConnected()
} // else if of ky.isReadable()
itr.remove();
} // end of while loop
} // end of for loop
}
public void processAndStore(String output) {
String exchangeName = null;
String dataLine = null;
String Lines[] = output.split("\r\n");
for (int i = 0; i < Lines.length; i++) {
if (Lines[i].contains("Host: ")) {
exchangeName = Lines[i].substring(6);
}
if (Lines[i].isEmpty()) {
dataLine = Lines[i + 1];
}
}
StringBuffer updatedLastLine = null;
if (dataLine != null) {
if (dataLine.contains("POST")) {
updatedLastLine = new StringBuffer(dataLine.substring(0, dataLine.indexOf("POST")));
} else {
updatedLastLine = new StringBuffer(dataLine);
}
if (!dataLine.equals("")) {
try {
if (updatedLastLine.lastIndexOf("}") != -1) {
updatedLastLine.replace(updatedLastLine.lastIndexOf("}"), updatedLastLine.lastIndexOf("}") + 1, ",\"name\":\"" + exchangeName
+ "\"}");
} else {
return;
}
} catch (StringIndexOutOfBoundsException e) {
System.out.println(updatedLastLine + "::" + dataLine);
System.out.println(e);
}
store(updatedLastLine.toString());
}
}
}
public NioReceiver(int port) {
this.port = port;
}
}
When I am removing processing logic it is able to receive more requests but not all.
how can I improve my code to receive all 10000s incoming requests.
Use a thread pool / message queue instead of creating 1000's of threads for calling processAndStore().
Starting a thread is expensive.
Starting 10000 threads per second? Yikes!
As #EJP said in a comment:
The purpose of NIO is to reduce the number of required threads. You don't seem to have got the message.
In addition to that, profile your code to see where the bottleneck is, rather than guessing.
But, here are some guesses anyway:
Don't use StringBuffer, use StringBuilder.
Reason: See Difference between StringBuilder and StringBuffer.
Don't call lastIndexOf("}") three times.
Reason: lastIndexOf() is a sequential search, so relatively slow. The JVM may or may not optimize the multiple calls away, but if performance is critical, don't rely on it. Do it yourself by assigning result to variable. See also Does Java optimize method calls via an interface which has a single implementor marked as final?
So ... I have a bit of software that's supposed to communicate with a memcached server (using no external libraries).
For testing purposes, let's settle on a simple get hello\r\n command.
I start memcached with the -vv option, this is what the command produces via telnet:
<15 new auto-negotiating client connection
15: Client using the ascii protocol
<15 get hello
>15 END
Now here is what the same command issued from my software produces:
<15 new auto-negotiating client connection
I'm connecting as following:
private void reconnect(){
InetSocketAddress remote;
int nofServers = m.servers.size();
for(int i = 0; i < R; ++i){
boolean success = false;
while(!success) {
try {
SocketChannel oldConnection = connections.get(i);
if (oldConnection != null) oldConnection.close();
remote = m.servers.get((myServerIndex + i) % nofServers).address();
SocketChannel chan = SocketChannel.open(remote);
chan.configureBlocking(false);
chan.register(this.selector, SelectionKey.OP_READ);
connections.set(i, chan);
success = true;
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
After that, the software falls into simple enough a NIO loop:
#Override
public void run() {
MyRequest curr = null;
this.canHandleNewRequest = true;
while (true) {
if (canHandleNewRequest) {
curr = myQueue.poll();
}
if (canHandleNewRequest && curr != null) {
canHandleNewRequest = false;
for (int i = 0; i < R; ++i) {
connections.get(i).keyFor(this.selector).interestOps(SelectionKey.OP_WRITE);
}
}
try {
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey k = it.next();
it.remove();
if (!k.isValid()) continue;
if (k.isConnectable()) finishConnection(k);
else if (k.isReadable()) this.read(k, curr);
else if (k.isWritable()) this.write(k, curr);
}
} catch (IOException ex) {
ex.printStackTrace();
reconnect();
}
if(curr != null && /*have sent to all servers I need to*/){
curr = null;
this.canHandleNewRequest = true;
}
}
}
where
private void write(SelectionKey k, MyRequest currentRequest){
try {
SocketChannel chan = (SocketChannel) k.channel();
ByteBuffer out = currentRequest.getSendBuffer(); //DO NOT FLIP (to resume sending from last sent position)
assert(chan != null);
assert(out != null);
//System.out.println(new String(out.array()));
chan.write(out); //TODO: make this work!
if(!out.hasRemaining()) { //do not enable read until whole command has been sent
currentRequest.partiallySent();
k.interestOps(SelectionKey.OP_READ);
}
}catch(IOException ex){
ex.printStackTrace();
}
//TODO: create response structure
}
I even tried to substitute the write method for a dummy command provider:
else if(k.isWritable()){
SocketChannel chan = (SocketChannel)k.channel();
ByteBuffer msg = ByteBuffer.wrap("get hello\r\n".getBytes());
msg.flip();
while(msg.hasRemaining()) {
System.out.println("writing ...");
chan.write(msg);
}
k.interestOps(SelectionKey.OP_READ);
}
but this only gets stuck in the "writing" loop (never terminates).
You should think that at least the server should react to that command but it doesn't.
So ... how do I get this working?
The second line from the log providing the command via telnet produces,
15: Client using the ascii protocol
makes me think there might be something I need to send to the server prior to engaging in actual memcached commands... except I seem to miss it in the protocol.
Help would be appreciated.
EDIT
This seems to be the issue: flipping a buffer in the getSendBuffer method and then returning it is not the same as returning it unflipped and then flipping it in the write method.
I find this rather strange. Can this be or is this merely masking a different error?
With NIO you should always check whether all of the buffer has been written, which is not being done doing in the first write block. Having said that, unless there's a lot of data being written, the whole buffer is usually written in a single call to write. So, it's unlikely to be the root problem here.
In the alternative writing code block the hasRemaining condition is negated, it should be:
while(msg.hasRemaining()) {
System.out.println("writing ...");
chan.write(msg);
}
Could you include what's being sent first? Is the first command terminated with \r\n?
I'm extending the BaseIOIOLooper to open up a UART device and send messages. I'm testing with a readback, where I send a packet over a line and receive that packet on another line and print it out. Because I don't want the InputStream.read() method to block, I am handling packet formation and input in a different thread. I have narrowed my problem down to the InputStream.read() method, which returns -1 (no bytes read, but no exception).
Here is what it looks like in the Looper thread:
#Override
protected void setup() throws ConnectionLostException, InterruptedException {
log_.write_log_line(log_header_ + "Beginning IOIO setup.");
// Initialize IOIO UART pins
// Input at pin 1, output at pin 2
try {
inQueue_ = MinMaxPriorityQueue.orderedBy(new ComparePackets())
.maximumSize(QUEUESIZE).create();
outQueue_ = MinMaxPriorityQueue.orderedBy(new ComparePackets())
.maximumSize(QUEUESIZE).create();
ioio_.waitForConnect();
uart_ = ioio_.openUart(1, 2, 38400, Uart.Parity.NONE, Uart.StopBits.ONE);
// Start InputHandler. Takes packets from ELKA on inQueue_
in_= new InputHandler(inQueue_, uart_.getInputStream());
in_.start();
// Start OutputHandler. Takes packets from subprocesses on outQueue_
out_= new OutputHandler(outQueue_);
out_.start();
// Get output stream
os_=uart_.getOutputStream();
// Set default target state
setTargetState(State.TRANSFERRING);
currInPacket_[0]=1; //Initial value to start transferring
log_.write_log_line(log_header_ + "IOIO setup complete.\n\t" +
"Input pin set to 1\n\tOutput pin set to 2\n\tBaud rate set to 38400\n\t" +
"Parity set to even\n\tStop bits set to 1");
} catch (IncompatibilityException e) {
log_.write_log_line(log_header_+e.toString());
} catch (ConnectionLostException e) {
log_.write_log_line(log_header_+e.toString());
} catch (Exception e) {
log_.write_log_line(log_header_+"mystery exception: "+e.toString());
}
}
And in the InputHandler thread:
#Override
public void run() {
boolean notRead;
byte i;
log_.write_log_line(log_header_+"Beginning InputHandler thread");
while (!stop) {
i = 0;
notRead = true;
nextInPacket = new byte[BUFFERSIZE];
readBytes = -1;
//StringBuilder s=new StringBuilder();
//TODO re-implement this with signals
while (i < READATTEMPTS && notRead) {
try {
// Make sure to adjust packet size. Done manually here for speed.
readBytes = is_.read(nextInPacket, 0, BUFFERSIZE);
/* Debugging
for (int j=0;j<nextInPacket.length;j++)
s.append(Byte.toString(nextInPacket[j]));
log_.write_log_line(log_header_+s.toString());
*/
if (readBytes != -1) {
notRead = false;
nextInPacket= new byte[]{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0};
synchronized (q_) {
q_.add(nextInPacket);
}
//log_.write_log_line(log_header_ + "Incoming packet contains valid data.");
} else i++;
} catch (IOException e) {
log_.write_log_line(log_header_ + "mystery exception:\n\t" + e.toString());
}
}
if (i>=READATTEMPTS)
log_.write_log_line(log_header_+"Too many read attempts from input stream.");
/*
try {
sleep(100);
} catch (InterruptedException e) {
log_.write_log_line(log_header_+"fuck");
}
*/
}
}
On an oscilloscope, pins 1 and 2 both read an oscillating voltage, albeit at a very high amplitude, which is of some concern. Point is nothing is available to be read from the InputStream in the InputHandler class. Any ideas?
-1 returned from read() should only happen whenever the UART is closed. The closure can happen as result of explicitly calling close() on the Uart object or calling softReset() on the IOIO object.
The Android log might give you some clues about what's going on.
The reading you're seeing on the oscilloscope is suspicious: how high is "very high amplitude"? You should only ever see 0V or 3.3V on those pins, or floating in case the pins where not opened (or closed) for some reason.
I am using an SSLEngine over Java NIO unblocking server sockets to handle connections. I am able to successfully handshake the clients and pass small record sets to the server. However when I try to transfer a file to the server text/binary I am getting the following error:
javax.net.ssl.SSLException: Unsupported record version Unknown-0.0
at sun.security.ssl.InputRecord.checkRecordVersion(InputRecord.java:552)
at sun.security.ssl.EngineInputRecord.bytesInCompletePacket(EngineInputRecord.java:113)
at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:862)
at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:775)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
at ncp.io.network.tls.TLSWrapper.unwrap(TLSWrapper.java:170)
at ncp.io.network.tls.TLSIO.decodeData(TLSIO.java:110)
at ncp.io.network.tls.TLSIO.handleRead(TLSIO.java:71)
at ncp.io.network.SocketThread.run(SocketThread.java:137)
I am however unable to find out the reason for this error.
Below is my code snippet
#Override
public int handleRead(ByteBuffer temp) {
int read = opsManager.handleRead(temp);
if (read > 0) {
try {
tlsDecodeBuffer = decodeData(temp);
try {
temp.clear();
temp.put(tlsDecodeBuffer);
}catch (BufferOverflowException e){
temp = ByteBuffer.allocateDirect(tlsDecodeBuffer.remaining());
temp.put(tlsDecodeBuffer);
}
temp.flip();
temp.rewind();
if(tlsDecodeBuffer.hasRemaining())
tlsDecodeBuffer.compact();
else
tlsDecodeBuffer.clear();
}catch (SSLException e){
// Error occurs here:
e.printStackTrace();
log.warning("Insecure connection attempted/ SSL failure for:" + e.getMessage());
opsManager.close();
}
catch (IOException e) {
e.printStackTrace();
}
return read;
} else {
return -1;
}
}
private ByteBuffer decodeData(ByteBuffer input) throws IOException {
ncp.io.network.tls.TLSStatus stat = null;
boolean continueLoop = true;
do {
tlsDecodeBuffer = wrapper.unwrap(input, tlsDecodeBuffer);
switch (wrapper.getStatus()) {
case NEED_WRITE:
writeBuff(ByteBuffer.allocate(0));
break;
case UNDERFLOW:
if (tlsDecodeBuffer.capacity() == tlsDecodeBuffer.remaining()) {
throw new BufferUnderflowException();
} else {
input.compact();
continueLoop = false;
}
break;
case CLOSED:
if (log.isLoggable(Level.FINER)) {
log.finer("TLS Socket closed..." + toString());
}
throw new EOFException("Socket has been closed.");
default:
break;
}
stat = wrapper.getStatus();
} while (continueLoop && ((stat == TLSStatus.NEED_READ) || (stat == TLSStatus.OK))
&& input.hasRemaining());
if (continueLoop) {
if (input.hasRemaining()) {
input.rewind();
} else {
input.clear();
}
}
tlsDecodeBuffer.flip();
return tlsDecodeBuffer;
}
Your code doesn't make sense.
When you get a BufferOverflowException in unwrap(), you need to empty the target buffer via flip()/get()/compact().
When you get a BufferOverflowException in wrap(), you need to empty the target buffer via flip()/write()/compact(), where the write() goes to the network.
In neither case does it make any sense to allocate a new buffer etc.
rewind() after flip() doesn't begin to make sense in any context.
There are numerous posts and answers here about how to use the SSLEngine properly. I suggest you read them thoroughly.