// File: maclellant[P]ReliableGoBackN/client.cpp
// Function: main
int main(int argc, char** argv)
{
    if(argc != 6) {
        std::cout << "Usage: " << argv[0] << " ";
        std::cout << "<client-port> <server-IP> <server-port> <func> <filename> \n";
        exit(EXIT_FAILURE);
    }

    unsigned short client_port = (unsigned short) strtoul(argv[1], NULL, 0);
    unsigned short server_port = (unsigned short) strtoul(argv[3], NULL, 0);
    char* type = argv[4];
    char* filename = argv[5];

    int sockfd;
    uint8_t packet_type = 255;
    struct sockaddr_in server;
    struct sockaddr_in client;
    socklen_t slen = sizeof(server);

    // Parse the given server IP address
    if(inet_aton(argv[2], &server.sin_addr) == 0)
    {
        std::cerr << "Error: Given IP address not valid: " << argv[2] << std::endl;
        exit(EXIT_FAILURE);
    }

    // Parse the function code
    else if (!strcmp(type, "GET"))
        packet_type = GET;

    if (packet_type == 255)
    {
        std::cerr << "Error: Given function command not valid: " << type << std::endl;
        std::cerr << "Please use GET" << std::endl;
        exit(EXIT_FAILURE);
    }

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "Error: Could not create client socket.\n\n";
        exit(EXIT_FAILURE);
    }

    // Set the timeout
    struct timeval tv;
    tv.tv_sec = TIMEOUT_SEC;
    tv.tv_usec = TIMEOUT_USEC;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));

    // Set all the information on the client address struct
    client.sin_family = AF_INET;
    client.sin_port = htons(client_port);
    client.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(sockfd, (struct sockaddr*) &client, sizeof(client)) == -1)
    {
        std::cerr << "Error: Could not bind client process to port " << client_port << std::endl;
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);

    std::cout << "Attempting to talk with server at " << argv[2] << ":" << argv[3] << std::endl;
    std::string str_filename(filename);

    request_func(sockfd, filename, str_filename.size(), server);
    //COMMENCE LISTENING
    receive_func(sockfd, filename, server);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x6, -0x8(%rbp)
je 0x27dd
movq 0x3832(%rip), %rdi      # 0x5fc8
leaq 0x1877(%rip), %rsi      # 0x4014
callq 0x21c0
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rsi
callq 0x21c0
movq %rax, %rdi
leaq 0x18e9(%rip), %rsi      # 0x40a4
callq 0x21c0
movq 0x3801(%rip), %rdi      # 0x5fc8
leaq 0x184e(%rip), %rsi      # 0x401c
callq 0x21c0
movl $0x1, %edi
callq 0x2240
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x20b0
movw %ax, -0x12(%rbp)
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x20b0
movw %ax, -0x14(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x28(%rbp)
movb $-0x1, -0x2d(%rbp)
movl $0x10, -0x54(%rbp)
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
leaq -0x40(%rbp), %rsi
addq $0x4, %rsi
callq 0x2130
cmpl $0x0, %eax
jne 0x2884
movq 0x37a1(%rip), %rdi      # 0x5ff0
leaq 0x1802(%rip), %rsi      # 0x4058
callq 0x21c0
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x21c0
movq %rax, %rdi
movq 0x3743(%rip), %rsi      # 0x5fb8
callq 0x21e0
movl $0x1, %edi
callq 0x2240
movq -0x20(%rbp), %rdi
leaq 0x1822(%rip), %rsi      # 0x40b1
callq 0x2260
cmpl $0x0, %eax
jne 0x289d
movb $0x2, -0x2d(%rbp)
jmp 0x289f
movzbl -0x2d(%rbp), %eax
cmpl $0xff, %eax
jne 0x2904
movq 0x373f(%rip), %rdi      # 0x5ff0
leaq 0x17c4(%rip), %rsi      # 0x407c
callq 0x21c0
movq %rax, %rdi
movq -0x20(%rbp), %rsi
callq 0x21c0
movq %rax, %rdi
movq 0x36e5(%rip), %rsi      # 0x5fb8
callq 0x21e0
movq 0x3711(%rip), %rdi      # 0x5ff0
leaq 0x17c0(%rip), %rsi      # 0x40a6
callq 0x21c0
movq %rax, %rdi
movq 0x36c3(%rip), %rsi      # 0x5fb8
callq 0x21e0
movl $0x1, %edi
callq 0x2240
movl $0x2, %esi
xorl %edx, %edx
movl %esi, %edi
callq 0x2090
movl %eax, -0x2c(%rbp)
cmpl $0x0, -0x2c(%rbp)
jge 0x2938
movq 0x36ce(%rip), %rdi      # 0x5ff0
leaq 0x178c(%rip), %rsi      # 0x40b5
callq 0x21c0
movl $0x1, %edi
callq 0x2240
movq $0x0, -0x68(%rbp)
movq $0xbb8, -0x60(%rbp)     # imm = 0xBB8
movl -0x2c(%rbp), %edi
movl $0x1, %esi
movl $0x14, %edx
leaq -0x68(%rbp), %rcx
movl $0x10, %r8d
callq 0x22f0
movw $0x2, -0x50(%rbp)
movzwl -0x12(%rbp), %edi
callq 0x2050
movw %ax, -0x4e(%rbp)
xorl %edi, %edi
callq 0x2140
movl %eax, -0x4c(%rbp)
movl -0x2c(%rbp), %edi
leaq -0x50(%rbp), %rsi
movl $0x10, %edx
callq 0x2070
cmpl $-0x1, %eax
jne 0x29d7
movq 0x3652(%rip), %rdi      # 0x5ff0
leaq 0x1739(%rip), %rsi      # 0x40de
callq 0x21c0
movq %rax, %rdi
movzwl -0x12(%rbp), %esi
callq 0x22b0
movq %rax, %rdi
movq 0x35f8(%rip), %rsi      # 0x5fb8
callq 0x21e0
movl -0x2c(%rbp), %edi
callq 0x2320
movl $0x1, %edi
callq 0x2240
movw $0x2, -0x40(%rbp)
movzwl -0x14(%rbp), %edi
callq 0x2050
movw %ax, -0x3e(%rbp)
movq 0x35d7(%rip), %rdi      # 0x5fc8
leaq 0x1714(%rip), %rsi      # 0x410c
callq 0x21c0
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
callq 0x21c0
movq %rax, %rdi
leaq 0x1718(%rip), %rsi      # 0x412f
callq 0x21c0
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rsi
callq 0x21c0
movq %rax, %rdi
movq 0x3582(%rip), %rsi      # 0x5fb8
callq 0x21e0
movq -0x28(%rbp), %rax
movq %rax, -0xd0(%rbp)
leaq -0x89(%rbp), %rdi
movq %rdi, -0xc8(%rbp)
callq 0x22e0
movq -0xd0(%rbp), %rsi
movq -0xc8(%rbp), %rdx
leaq -0x88(%rbp), %rdi
callq 0x3460
jmp 0x2a75
leaq -0x89(%rbp), %rdi
callq 0x2200
movl -0x2c(%rbp), %eax
movl %eax, -0xdc(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0xd8(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x2110
movl -0xdc(%rbp), %edi
movq -0xd8(%rbp), %rsi
movq %rax, %rdx
movups -0x40(%rbp), %xmm0
movaps %xmm0, -0xb0(%rbp)
movq -0xb0(%rbp), %rcx
movq -0xa8(%rbp), %r8
callq 0x2b60
jmp 0x2ad1
movl -0x2c(%rbp), %edi
movq -0x28(%rbp), %rsi
movups -0x40(%rbp), %xmm0
movaps %xmm0, -0xc0(%rbp)
movq -0xc0(%rbp), %rdx
movq -0xb8(%rbp), %rcx
callq 0x2bf0
jmp 0x2af8
leaq -0x88(%rbp), %rdi
callq 0x20f0
movl -0x4(%rbp), %eax
addq $0xe0, %rsp
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x89(%rbp), %rdi
callq 0x2200
jmp 0x2b4e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x20f0
movq -0x98(%rbp), %rdi
callq 0x22d0
nopw (%rax,%rax)