Почему в виртуальном потоке startHandshake блокируется?JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Почему в виртуальном потоке startHandshake блокируется?

Сообщение Anonymous »

Код: Выделить всё

public class Main {

public static SSLContext sslContext = null; // some sslContext

public static void main(String[] args) throws IOException {
startServer();
// startClient(); // is ok
Thread.ofVirtual().start(() -> {
try {
startClient(); // why blocking ?
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}

public static void startServer() throws IOException {
var serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(true);
serverSocketChannel.bind(new InetSocketAddress(8080));
Thread.ofPlatform().start(() -> {
while (true) {
try {
var socketChannel = serverSocketChannel.accept();
var sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
var tlsSocketChannel = new TLSSocketChannel(socketChannel, sslEngine);

tlsSocketChannel.startHandshake();

System.out.println("server SSL handshake success");

} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}

public static void startClient() throws IOException {

var socketChannel = SocketChannel.open();
var sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(true);

var tlsSocketChannel = new TLSSocketChannel(socketChannel, sslEngine);
tlsSocketChannel.configureBlocking(true);
tlsSocketChannel.connect(new InetSocketAddress(8080));

tlsSocketChannel.startHandshake();
System.out.println("client SSL handshake success");

}

}

Код: Выделить всё

public class TLSSocketChannel extends AbstractSocketChannel {

private final SSLEngine sslEngine;

private ByteBuffer outboundNetData;

private ByteBuffer inboundNetData;

private ByteBuffer inboundAppData;

public TLSSocketChannel(SocketChannel socketChannel, SSLEngine sslEngine) {
super(socketChannel);
this.sslEngine = sslEngine;

this.outboundNetData = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
this.inboundNetData = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
this.inboundAppData = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
this.inboundAppData.flip();
}

public void startHandshake() throws IOException {
sslEngine.beginHandshake();

_MAIN:
while (true) {
var handshakeStatus = sslEngine.getHandshakeStatus();
switch (handshakeStatus) {
case NEED_UNWRAP -> {

_NU:
while (true) {

if (socketChannel.read(inboundNetData) == -1) {
throw new SSLHandshakeException("Channel closed during handshake");
}

inboundNetData.flip();

var result = sslEngine.unwrap(inboundNetData, ByteBuffer.allocate(0));
switch (result.getStatus()) {
case OK -> {
break _NU;
}
case BUFFER_OVERFLOW -> {
throw new SSLHandshakeException("Unexpected buffer overflow");
}
case BUFFER_UNDERFLOW -> {
int remainingSpace = inboundNetData.capacity() - inboundNetData.limit();
if (remainingSpace == 0) {
var newInboundNetData = ByteBuffer.allocate(inboundNetData.capacity() * 2);
newInboundNetData.put(inboundNetData);
inboundNetData = newInboundNetData;
}
}
case CLOSED ->  {
throw new SSLHandshakeException("closed on handshake wrap");
}
}
}

inboundNetData.compact();
}
case NEED_WRAP -> {

outboundNetData.clear();

_NW:
while (true) {

var result = sslEngine.wrap(ByteBuffer.allocate(0), outboundNetData);
switch (result.getStatus()) {
case OK -> {

outboundNetData.flip();

while (outboundNetData.hasRemaining()) {
socketChannel.write(outboundNetData);
}
break _NW;
}
case BUFFER_OVERFLOW -> {
outboundNetData = ByteBuffer.allocate(outboundNetData.capacity() * 2);
}
case BUFFER_UNDERFLOW -> {
throw new SSLHandshakeException("buffer underflow on handshake wrap");
}
case CLOSED -> {
throw new SSLHandshakeException("closed on handshake wrap");
}
}
}
}
case NEED_TASK -> {
while (true) {
var task = sslEngine.getDelegatedTask();
if (task == null) {
break;
}
task.run();
}
}
case FINISHED -> {
break _MAIN;
}
case NOT_HANDSHAKING -> {
break _MAIN;
}
}
}
}

@Override
public int read(ByteBuffer dst) throws IOException {

if (inboundAppData.hasRemaining()) {
return transferByteBuffer(inboundAppData, dst);
}

inboundAppData.clear();

var totalBytesConsumed = 0;
var totalBytesProduced = 0;

_R:
while (true) {

var bytesRead = socketChannel.read(inboundNetData);

if (bytesRead == -1) {
return -1;
}

inboundNetData.flip();

_UW:
while (inboundNetData.hasRemaining()) {

var result = sslEngine.unwrap(inboundNetData, inboundAppData);

totalBytesConsumed += result.bytesConsumed();
totalBytesProduced += result.bytesProduced();

switch (result.getStatus()) {
case OK -> {

}
case BUFFER_OVERFLOW -> {
var newAppBuffer = ByteBuffer.allocate(inboundAppData.capacity() * 2);
newAppBuffer.put(inboundAppData.flip());
inboundAppData = newAppBuffer;
}
case BUFFER_UNDERFLOW -> {

if (totalBytesProduced > 0) {
break _UW;
}

var newNetBuffer = ByteBuffer.allocate(inboundNetData.capacity() * 2);
newNetBuffer.put(inboundNetData);
inboundNetData = newNetBuffer;
continue _R;
}
case CLOSED -> {
break _R;
}
}
}

break;
}

inboundNetData.compact();

inboundAppData.flip();

return transferByteBuffer(inboundAppData, dst);
}

@Override
public int write(ByteBuffer src) throws IOException {
int n = 0;

while (src.hasRemaining()) {

outboundNetData.clear();

var result = sslEngine.wrap(src, outboundNetData);

switch (result.getStatus()) {
case OK ->  {

outboundNetData.flip();

while (outboundNetData.hasRemaining()) {
socketChannel.write(outboundNetData);
}
n += result.bytesConsumed();
}
case BUFFER_OVERFLOW -> {
outboundNetData = ByteBuffer.allocate(outboundNetData.capacity() * 2);
}
case BUFFER_UNDERFLOW -> {
throw new IOException("SSLEngine wrap BUFFER_UNDERFLOW");
}
case CLOSED -> {
throw new IOException("SSLEngine wrap CLOSED");
}
}
}

return n;
}

@Override
protected void implCloseSelectableChannel() throws IOException {
sslEngine.closeOutbound();
socketChannel.close();
}

public static int transferByteBuffer(ByteBuffer source, ByteBuffer dest) {
int sourceRemaining = source.remaining();
int destRemaining = dest.remaining();
if (sourceRemaining > destRemaining) {
int originalLimit = source.limit();
source.limit(source.position() + destRemaining);
dest.put(source);
source.limit(originalLimit);
return destRemaining;
} else {
dest.put(source);
return sourceRemaining;
}
}

}
AbstractSocketChannel просто делегирует некоторые менее важные методы. Поэтому я не стал размещать это здесь.
Я пишу TLSSocketChannel.
Но когда я запускаю клиент в виртуальном потоке, startHandshake блокируется, почему ?
Когда я пытаюсь выполнить System.out.println("xxx") на TLSSocketChannel.startHandshake, иногда не происходит блокировка?
В потоке платформы никогда не блокируется .

Подробнее здесь: https://stackoverflow.com/questions/793 ... l-blocking
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»