Код: Выделить всё
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;
}
}
}
Я пишу TLSSocketChannel.
Но когда я запускаю клиент в виртуальном потоке, startHandshake блокируется, почему ?
Когда я пытаюсь выполнить System.out.println("xxx") на TLSSocketChannel.startHandshake, иногда не происходит блокировка?
В потоке платформы никогда не блокируется .
Подробнее здесь: https://stackoverflow.com/questions/793 ... l-blocking