There is no indication that the sockets are leaking in the handling
loop, but its good to be careful and ensure we always both close
the SocketChannel and cancel the key registration.
During connection, however, it appears we may leak a SocketChannel
if the connection times out, leaking a file descriptor at least
until the GC kicks in and cleans up after us. Here we are more
careful.
(peer.key.interestOps() | SelectionKey.OP_READ) & (~SelectionKey.OP_WRITE)));
}
return written;
(peer.key.interestOps() | SelectionKey.OP_READ) & (~SelectionKey.OP_WRITE)));
}
return written;
- } catch (IOException e) {
+ } catch (IOException|CancelledKeyException ignored) {
// Most likely the socket is disconnected, let the background thread handle it.
return 0;
}
// Most likely the socket is disconnected, let the background thread handle it.
return 0;
}
public void disconnect_socket() {
try {
do_selector_action(() -> {
public void disconnect_socket() {
try {
do_selector_action(() -> {
+ try { peer.key.cancel(); } catch (CancelledKeyException ignored) {}
peer.key.channel().close();
});
} catch (IOException ignored) { }
peer.key.channel().close();
});
} catch (IOException ignored) { }
if (key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) != 0 && key.isWritable()) {
Result_NonePeerHandleErrorZ res = this.peer_manager.write_buffer_space_avail(peer.descriptor);
if (res instanceof Result_NonePeerHandleErrorZ.Result_NonePeerHandleErrorZ_Err) {
if (key.isValid() && (key.interestOps() & SelectionKey.OP_WRITE) != 0 && key.isWritable()) {
Result_NonePeerHandleErrorZ res = this.peer_manager.write_buffer_space_avail(peer.descriptor);
if (res instanceof Result_NonePeerHandleErrorZ.Result_NonePeerHandleErrorZ_Err) {
}
}
if (key.isValid() && (key.interestOps() & SelectionKey.OP_READ) != 0 && key.isReadable()) {
}
}
if (key.isValid() && (key.interestOps() & SelectionKey.OP_READ) != 0 && key.isReadable()) {
if (read == -1) {
this.peer_manager.socket_disconnected(peer.descriptor);
key.cancel();
if (read == -1) {
this.peer_manager.socket_disconnected(peer.descriptor);
key.cancel();
+ key.channel().close(); // This may throw, we read -1 so the channel should already be closed, but do this to be safe
} else if (read > 0) {
((Buffer)buf).flip();
// This code is quite hot during initial network graph sync, so we go a ways out of
} else if (read > 0) {
((Buffer)buf).flip();
// This code is quite hot during initial network graph sync, so we go a ways out of
key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
}
} else {
key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
}
} else {
}
bindings.CResult_boolPeerHandleErrorZ_free(read_result_pointer);
}
}
} catch (IOException ignored) {
}
bindings.CResult_boolPeerHandleErrorZ_free(read_result_pointer);
}
}
} catch (IOException ignored) {
- try { key.channel().close(); } catch (IOException ignored2) { }
+ try { key.channel().close(); } catch (IOException ignored2) { }
peer_manager.socket_disconnected(peer.descriptor);
}
} catch (CancelledKeyException e) {
peer_manager.socket_disconnected(peer.descriptor);
}
} catch (CancelledKeyException e) {
*/
public void connect(byte[] their_node_id, SocketAddress remote, int timeout_ms) throws IOException {
SocketChannel chan = SocketChannel.open();
*/
public void connect(byte[] their_node_id, SocketAddress remote, int timeout_ms) throws IOException {
SocketChannel chan = SocketChannel.open();
- chan.configureBlocking(false);
- Selector open_selector = Selector.open();
- chan.register(open_selector, SelectionKey.OP_CONNECT);
- if (!chan.connect(remote)) {
- open_selector.select(timeout_ms);
+ boolean connected;
+ try {
+ chan.configureBlocking(false);
+ Selector open_selector = Selector.open();
+ chan.register(open_selector, SelectionKey.OP_CONNECT);
+ if (!chan.connect(remote)) {
+ open_selector.select(timeout_ms);
+ }
+ connected = chan.finishConnect();
+ } catch (IOException e) {
+ try { chan.close(); } catch (IOException _e) { }
+ throw e;
- if (!chan.finishConnect()) { // Note that this may throw its own IOException if we failed for another reason
+ if (!connected) {
+ try { chan.close(); } catch (IOException _e) { }
throw new IOException("Timed out");
}
Peer peer = setup_socket(chan);
throw new IOException("Timed out");
}
Peer peer = setup_socket(chan);