Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: accept tracker connections #187

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;

import static java.util.concurrent.TimeUnit.MINUTES;

Expand All @@ -35,9 +35,10 @@ public class ConnectionHandler {
public static final int PORT_RANGE_START = 49152;
public static final int PORT_RANGE_END = 65534;

private ServerSocketChannel channel;
private ServerSocketChannel listenChannel;
@Getter private InetAddress ipAddress;
private Thread ipFetcherThread;
private Thread serverThread;
private static final String[] IP_PROVIDERS = new String[]{
"http://whatismyip.akamai.com",
"http://ipecho.net/plain",
Expand All @@ -51,19 +52,19 @@ public class ConnectionHandler {
};

public int getPort() {
return this.channel.socket().getLocalPort();
return this.listenChannel.socket().getLocalPort();
}

public void start() throws IOException {
this.channel = this.bindToPort();
this.listenChannel = this.bindToPort();
log.info("Listening for incoming peer connections on port {}", getPort());

this.ipAddress = fetchIp();
log.info("IP reported to tracker will be: {}", this.getIpAddress().getHostAddress());

// TODO: use @Scheduled
this.ipFetcherThread = new Thread(() -> {
while (this.ipFetcherThread == null || !this.ipFetcherThread.isInterrupted()) {
while (this.ipFetcherThread != null && !this.ipFetcherThread.isInterrupted()) {
try {
MINUTES.sleep(90); // TODO: move to config
this.ipAddress = this.fetchIp();
Expand All @@ -76,6 +77,29 @@ public void start() throws IOException {
});

this.ipFetcherThread.start();

this.serverThread = new Thread(() -> {
try {
Selector selector = Selector.open();
this.listenChannel.register(selector, SelectionKey.OP_ACCEPT);

while (this.listenChannel != null && this.serverThread != null && !this.serverThread.isInterrupted()) {
selector.select();
for (SelectionKey key : selector.selectedKeys()) {
if (key.isAcceptable()) {
this.listenChannel.accept();
Copy link
Contributor Author

@laur89 laur89 Feb 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note no I/O is done here at the moment, we only accept the connection. Any ideas how to proceed, if at all?

Copy link
Owner

@anthonyraymond anthonyraymond Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macro vision is:

  • When a peer connect though bittorrent protocol => send a choke message

But "connect through bittorrent protocol" is easier said than done 😆 .

it's something related to : https://github.com/mpetazzoni/ttorrent/blob/2c8bb62f9f69b74c014358d446554df96ec91c7c/ttorrent-client/src/main/java/com/turn/ttorrent/client/network/HandshakeReceiver.java#L148

Instead of adding peers to whatever store you'll just choke them (maybe close connection?).

This feature require a deep comprehension of the peer section of BitTorrent RFC (and also to investigate the source code of libtorrent and other OpenSource clients to understand how they individualy do their job).

}
}
}
} catch (ClosedChannelException e) {
log.debug("channel already closed", e);
} catch (IOException ioe) {
log.warn("Problem in server loop", ioe);
throw new RuntimeException(ioe);
}
});

this.serverThread.start();
}

@VisibleForTesting
Expand Down Expand Up @@ -156,23 +180,30 @@ ServerSocketChannel bindToPort() throws IOException {

public void close() {
log.debug("Closing ConnectionHandler...");

try {
if (this.channel != null) {
this.channel.close();
if (this.ipFetcherThread != null) {
this.ipFetcherThread.interrupt();
}

if (this.serverThread != null) {
this.serverThread.interrupt();
}
} catch (final Exception e) {
log.warn("ConnectionHandler channel has failed to release channel, but the shutdown will proceed", e);
} finally {
this.channel = null;
this.ipFetcherThread = null;
this.serverThread = null;
}

try {
if (this.ipFetcherThread != null) {
this.ipFetcherThread.interrupt();
if (this.listenChannel != null) {
this.listenChannel.close();
}
} catch (final Exception e) {
log.warn("ConnectionHandler channel has failed to release channel, but the shutdown will proceed", e);
} finally {
this.ipFetcherThread = null;
this.listenChannel = null;
}

log.debug("ConnectionHandler closed");
}
}