<commit_before>"""
Peer wire protocol (TCP)

The peer protocol facilitates the exchange of pieces as described in the
'metainfo file (.torrent file). Note here that the original specification also
used the term "piece" when describing the peer protocol, but as a different term
than "piece" in the metainfo file. For that reason, the term "block" will be
used in this specification to describe the data that is exchanged between peers
over the wire.
"""

from __future__ import (
    absolute_import,
    division,
    print_function,
    unicode_literals
)

import socket
import struct
import sys
from socketthread import receive_all


if sys.version_info.major == 2:
    chr = unichr
    string_type = basestring
elif sys.version_info.major == 3:
    # chr should assume Unicode
    string_type = str

LENGTH_PREFIX_SIZE = 4


class HandshakeException(Exception):
    """
    Base exception for peer wire hand shake
    """

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    def __str__(self):
        return "{}:{} Refused the handshake".format(self.ip, self.port)


def generate_handshake(info_hash, peer_id):
    """
    The handshake is a required message and must be the first message
    transmitted by the client. It is (49+len(pstr)) bytes long in the form:

    <pstrlen><pstr><reserved><info_hash><peer_id>

    Where:
    pstrlen: string length of <pstr>, as a single raw byte
    pstr: string identifier of the protocol
    reserved: eight (8) reserved bytes. All current implementations use all
     zeroes. Each bit in these bytes can be used to change the behavior of the
     protocol.
    info_hash: 20-byte SHA1 hash of the info key in the meta info file. This is
     the same info_hash that is transmitted in tracker requests.
    peer_id: 20-byte string used as a unique ID for the client. This is usually
     the same peer_id that is transmitted in tracker requests

    In version 1.0 of the BitTorrent protocol:
    pstrlen = 19 and pstr = "BitTorrent protocol".

    :param info_hash:
    :param peer_id:
    :return:
    """
    pstr = b"BitTorrent protocol"
    pstrlen = bytes(chr(len(pstr)))

    reserved = b"\x00" * 8  # 8 zeroes

    handshake = pstrlen + pstr + reserved + info_hash + peer_id

    assert len(handshake) == 49 + len(pstr)
    assert pstrlen == bytes(chr(19))

    return handshake


def send_handshake(handshake, ip, port):
    """
    Opens a connection to the given ip, port tries to send the handshake.

    :param handshake: The handshake that is send
    :param ip: The ip that the socket is opened on
    :param port: The port the receiver is listening on.
    :return: The open Socket and the response data
    :raise HandshakeException: a HandshakeException is raised if unable to
    establish connection or the handshake was refused.
    """
    address = (ip, port)

    tcp_sock = socket.socket(socket.AF_INET,
                             socket.SOCK_STREAM)  # tcp connection

    try:
        tcp_sock.connect(address)

        tcp_sock.send(handshake)

        response_data = receive_all(tcp_sock, len(handshake))

        if response_data is None:
            tcp_sock.close()
            raise HandshakeException(ip, port)
    except socket.error:
        tcp_sock.close()
        raise HandshakeException(ip, port)

    return tcp_sock, response_data


def decode_handshake(handshake):<commit_msg>Correctly handled invalid handshakes<commit_after>"""
Peer wire protocol (TCP)

The peer protocol facilitates the exchange of pieces as described in the
'metainfo file (.torrent file). Note here that the original specification also
used the term "piece" when describing the peer protocol, but as a different term
than "piece" in the metainfo file. For that reason, the term "block" will be
used in this specification to describe the data that is exchanged between peers
over the wire.
"""

from __future__ import (
    absolute_import,
    division,
    print_function,
    unicode_literals
)

import socket
import struct
import sys
from socketthread import receive_all


if sys.version_info.major == 2:
    chr = unichr
    string_type = basestring
elif sys.version_info.major == 3:
    # chr should assume Unicode
    string_type = str

LENGTH_PREFIX_SIZE = 4


class HandshakeException(Exception):
    """
    Base exception for peer wire hand shake
    """

    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    def __str__(self):
        return "{}:{} Refused the handshake".format(self.ip, self.port)


def generate_handshake(info_hash, peer_id):
    """
    The handshake is a required message and must be the first message
    transmitted by the client. It is (49+len(pstr)) bytes long in the form:

    <pstrlen><pstr><reserved><info_hash><peer_id>

    Where:
    pstrlen: string length of <pstr>, as a single raw byte
    pstr: string identifier of the protocol
    reserved: eight (8) reserved bytes. All current implementations use all
     zeroes. Each bit in these bytes can be used to change the behavior of the
     protocol.
    info_hash: 20-byte SHA1 hash of the info key in the meta info file. This is
     the same info_hash that is transmitted in tracker requests.
    peer_id: 20-byte string used as a unique ID for the client. This is usually
     the same peer_id that is transmitted in tracker requests

    In version 1.0 of the BitTorrent protocol:
    pstrlen = 19 and pstr = "BitTorrent protocol".

    :param info_hash:
    :param peer_id:
    :return:
    """
    pstr = b"BitTorrent protocol"
    pstrlen = bytes(chr(len(pstr)))

    reserved = b"\x00" * 8  # 8 zeroes

    handshake = pstrlen + pstr + reserved + info_hash + peer_id

    assert len(handshake) == 49 + len(pstr)
    assert pstrlen == bytes(chr(19))

    return handshake


def send_handshake(handshake, ip, port):
    """
    Opens a connection to the given ip, port tries to send the handshake.

    :param handshake: The handshake that is send
    :param ip: The ip that the socket is opened on
    :param port: The port the receiver is listening on.
    :return: The open Socket and the response data
    :raise HandshakeException: a HandshakeException is raised if unable to
    establish connection or the handshake was refused.
    """
    address = (ip, port)

    tcp_sock = socket.socket(socket.AF_INET,
                             socket.SOCK_STREAM)  # tcp connection

    try:
        tcp_sock.connect(address)

        tcp_sock.send(handshake)

        response_data = receive_all(tcp_sock, len(handshake))

        # The handshake is specified to be (49+len(pstr)) bytes long so we can
        # assume that it should be at least 49 bytes long
        if len(response_data) < 49:
            tcp_sock.close()
            raise HandshakeException(ip, port)
    except socket.error:
        tcp_sock.close()
        raise HandshakeException(ip, port)

    return tcp_sock, response_data


def decode_handshake(handshake):
{'fraction_non_alphanumeric': 0.0708751793400287, 'fraction_numerical': 0.007460545193687231, 'mean_word_length': 3.029479768786127, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '3565970', 'n_tokens_mistral': 2068, 'n_tokens_neox': 1965, 'n_words': 807}