import struct
import socket
import select
import random

ICMP_CODE = socket.getprotobyname('icmp')


def checksum(source_string):
    sum = 0
    count_to = (len(source_string) / 2) * 2
    count = 0
    while count < count_to:
        this_val = source_string[count + 1]*256+source_string[count]
        sum = sum + this_val
        sum = sum & 0xffffffff
        count = count + 2
    if count_to < len(source_string):
        sum = sum + source_string[len(source_string) - 1]
        sum = sum & 0xffffffff
    sum = (sum >> 16) + (sum & 0xffff)
    sum = sum + (sum >> 16)
    answer = ~sum
    answer = answer & 0xffff
    answer = answer >> 8 | (answer << 8 & 0xff00)
    return answer

def create_packet(id, data):
    ICMP_ECHO_REQUEST = 8 # Код типа ICMP - в нашем случае ECHO
    header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, 0, id, 1)
    data = data
    my_checksum = checksum(header + data)
    header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), id, 1)
    return header + data


def send(dest_addr,data):
    my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, ICMP_CODE)
    host = socket.gethostbyname(dest_addr)

    packet_id = random.randint(0,65535)
    packet = create_packet(packet_id,data)
    
    while packet:
        sent = my_socket.sendto(packet, (dest_addr, 1))
        packet = packet[sent:]

    return my_socket, packet_id


def recv(my_socket, packet_id):
    ready = select.select([my_socket], [], [], 2) # таймаут 2с
    rec_packet, addr = my_socket.recvfrom(1024)
    icmp_header = rec_packet[20:28]    # Байты с 20 по 28 - заголовок ICMP
    type, code, checksum, p_id, sequence = struct.unpack(
            'bbHHh', icmp_header)

    data = rec_packet[28:] # Наш hello будет лежать после заголовка ICMP
    return data



def main():
    sock, id=send("8.8.8.8",b"hohoho")
    print(recv(sock,id))


if __name__ == '__main__':
    main()