<commit_before>/*
 *    This file is part of mlDHT.
 * 
 *    mlDHT is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 2 of the License, or
 *    (at your option) any later version.
 * 
 *    mlDHT is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 * 
 *    You should have received a copy of the GNU General Public License
 *    along with mlDHT.  If not, see <http://www.gnu.org/licenses/>.
 */
package the8472.bt;

import the8472.bencode.BDecoder;
import the8472.bencode.BEncoder;
import the8472.bt.MetadataPool.Completion;

import lbms.plugins.mldht.kad.DHT;
import lbms.plugins.mldht.kad.DHT.LogLevel;
import lbms.plugins.mldht.kad.Key;
import lbms.plugins.mldht.kad.utils.AddressUtils;
import lbms.plugins.mldht.kad.utils.ThreadLocalUtils;
import lbms.plugins.mldht.utils.NIOConnectionManager;
import lbms.plugins.mldht.utils.Selectable;
import static the8472.bt.PullMetaDataConnection.CONNECTION_STATE.*;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.IntFunction;

public class PullMetaDataConnection implements Selectable {
	
	public static interface InfohashChecker {
		boolean isInfohashAcceptable(byte[] hash);
	}
	
	public static interface MetaConnectionHandler {
		
		void onTerminate(boolean wasConnected);
		default void onStateChange(CONNECTION_STATE oldState, CONNECTION_STATE newState) {};
		void onConnect();
	}
	
	public final static byte[] preamble = "\u0013BitTorrent protocol".getBytes(StandardCharsets.ISO_8859_1);

	
	public static final byte[] bitfield = new byte[8];
	static {
		// ltep
		bitfield[5] |= 0x10;
		// fast extension
		bitfield[7] |= 0x04;
		// BT port
		bitfield[7] |= 0x01;
	}
	
	public enum CONNECTION_STATE {
		STATE_INITIAL,
		STATE_CONNECTING,
		STATE_BASIC_HANDSHAKING,
		STATE_LTEP_HANDSHAKING,
		STATE_PEX_ONLY,
		STATE_GETTING_METADATA,
		STATE_CLOSED,
	}
	

	
	private static final int RCV_TIMEOUT = 25*1000;
	
	private static final int LTEP_HEADER_ID = 20;
	private static final int LTEP_HANDSHAKE_ID = 0;
	private static final int LTEP_LOCAL_META_ID = 7;
	private static final int LTEP_LOCAL_PEX_ID = 13;
	
	private static final int BT_BITFIELD_ID = 5;
	
	private static final int BT_HEADER_LENGTH = 4;
	private static final int BT_MSG_ID_OFFSET = 4; // 0-3 length, 4 id
	private static final int BT_LTEP_HEADER_OFFSET =  5; // 5 ltep id
	
	boolean						keepPexOnlyOpen = true;
	
	SocketChannel				channel;
	NIOConnectionManager		connManager;
	boolean						incoming;
	
	Deque<ByteBuffer>			outputBuffers			= new LinkedList<>();
	ByteBuffer					inputBuffer;

	boolean						remoteSupportsFastExtension;
	boolean						remoteSupportsPort;
	int							ltepRemoteMetadataExchangeMessageId;
	int							ltepRemotePexId = -1;
	public int					dhtPort = -1;
	
	
	MetadataPool				pool;
	InfohashChecker				checker;
	byte[]						infoHash;

	int							outstandingRequests;
	int							maxRequests = 1;
	
	long						lastReceivedTime;
	int							consecutiveKeepAlives;
	
	CONNECTION_STATE			state;
	
	BDecoder					decoder = new BDecoder();
	MetaConnectionHandler		metaHandler;
	
	InetSocketAddress			destination;
	String 						remoteClient;
	
	public Consumer<List<InetSocketAddress>> pexConsumer = (x) -> {};
	public IntFunction<MetadataPool> 	poolGenerator = (i) -> new MetadataPool(i);
	
	static PrintWriter idWriter;
	
	static {
		try
		{
			idWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./peer_ids.log",true))),true);
		} catch (FileNotFoundException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void keepPexOnlyOpen(boolean toggle) {
		keepPexOnlyOpen = toggle;
	}
	
	void setState(CONNECTION_STATE newState) {
		CONNECTION_STATE oldState = state;
		state = newState;<commit_msg>uninitialized value, caused incorrect connection accounting<commit_after>/*
 *    This file is part of mlDHT.
 * 
 *    mlDHT is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 2 of the License, or
 *    (at your option) any later version.
 * 
 *    mlDHT is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 * 
 *    You should have received a copy of the GNU General Public License
 *    along with mlDHT.  If not, see <http://www.gnu.org/licenses/>.
 */
package the8472.bt;

import the8472.bencode.BDecoder;
import the8472.bencode.BEncoder;
import the8472.bt.MetadataPool.Completion;

import lbms.plugins.mldht.kad.DHT;
import lbms.plugins.mldht.kad.DHT.LogLevel;
import lbms.plugins.mldht.kad.Key;
import lbms.plugins.mldht.kad.utils.AddressUtils;
import lbms.plugins.mldht.kad.utils.ThreadLocalUtils;
import lbms.plugins.mldht.utils.NIOConnectionManager;
import lbms.plugins.mldht.utils.Selectable;
import static the8472.bt.PullMetaDataConnection.CONNECTION_STATE.*;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.IntFunction;

public class PullMetaDataConnection implements Selectable {
	
	public static interface InfohashChecker {
		boolean isInfohashAcceptable(byte[] hash);
	}
	
	public static interface MetaConnectionHandler {
		
		void onTerminate(boolean wasConnected);
		default void onStateChange(CONNECTION_STATE oldState, CONNECTION_STATE newState) {};
		void onConnect();
	}
	
	public final static byte[] preamble = "\u0013BitTorrent protocol".getBytes(StandardCharsets.ISO_8859_1);

	
	public static final byte[] bitfield = new byte[8];
	static {
		// ltep
		bitfield[5] |= 0x10;
		// fast extension
		bitfield[7] |= 0x04;
		// BT port
		bitfield[7] |= 0x01;
	}
	
	public enum CONNECTION_STATE {
		STATE_INITIAL,
		STATE_CONNECTING,
		STATE_BASIC_HANDSHAKING,
		STATE_LTEP_HANDSHAKING,
		STATE_PEX_ONLY,
		STATE_GETTING_METADATA,
		STATE_CLOSED,
	}
	

	
	private static final int RCV_TIMEOUT = 25*1000;
	
	private static final int LTEP_HEADER_ID = 20;
	private static final int LTEP_HANDSHAKE_ID = 0;
	private static final int LTEP_LOCAL_META_ID = 7;
	private static final int LTEP_LOCAL_PEX_ID = 13;
	
	private static final int BT_BITFIELD_ID = 5;
	
	private static final int BT_HEADER_LENGTH = 4;
	private static final int BT_MSG_ID_OFFSET = 4; // 0-3 length, 4 id
	private static final int BT_LTEP_HEADER_OFFSET =  5; // 5 ltep id
	
	boolean						keepPexOnlyOpen = true;
	
	SocketChannel				channel;
	NIOConnectionManager		connManager;
	boolean						incoming;
	
	Deque<ByteBuffer>			outputBuffers			= new LinkedList<>();
	ByteBuffer					inputBuffer;

	boolean						remoteSupportsFastExtension;
	boolean						remoteSupportsPort;
	int							ltepRemoteMetadataExchangeMessageId;
	int							ltepRemotePexId = -1;
	public int					dhtPort = -1;
	
	
	MetadataPool				pool;
	InfohashChecker				checker;
	byte[]						infoHash;

	int							outstandingRequests;
	int							maxRequests = 1;
	
	long						lastReceivedTime;
	int							consecutiveKeepAlives;
	
	CONNECTION_STATE			state = STATE_INITIAL;
	
	BDecoder					decoder = new BDecoder();
	MetaConnectionHandler		metaHandler;
	
	InetSocketAddress			destination;
	String 						remoteClient;
	
	public Consumer<List<InetSocketAddress>> pexConsumer = (x) -> {};
	public IntFunction<MetadataPool> 	poolGenerator = (i) -> new MetadataPool(i);
	
	static PrintWriter idWriter;
	
	static {
		try
		{
			idWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("./peer_ids.log",true))),true);
		} catch (FileNotFoundException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void keepPexOnlyOpen(boolean toggle) {
		keepPexOnlyOpen = toggle;
	}
	
	void setState(CONNECTION_STATE newState) {
		CONNECTION_STATE oldState = state;
		state = newState;
{'fraction_non_alphanumeric': 0.08055672711935892, 'fraction_numerical': 0.01433994095318431, 'mean_word_length': 4.143709327548807, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2000536', 'n_tokens_mistral': 3404, 'n_tokens_neox': 3010, 'n_words': 797}