// File: /workspace/github_cpp_makefile_star2_O3/maclellant[P]ReliableGoBackN/client.cpp
// Function: receive_func(int, char*, sockaddr_in)
void receive_func(int sockfd, char* filename, sockaddr_in server)
{
    socklen_t slen = sizeof(server);
    Packet packet;
    int cur_seq;
    int exp_seq = 0;
    bool send_ack = false;
    bool send_nak = false;
    FILE *outfile;
    outfile = fopen(filename, "wb");

    bool running = true;
    int timeout_amount = 0;
    while(running)
    {

        if (recvfrom(sockfd, packet.buffer, PACKET_SIZE, 0, (struct sockaddr*)&server, &slen)==-1)
        {
            if (errno == EWOULDBLOCK)
            {
                errno = 0;
                std::cout << "TIMEOUT: Server not responding...\n\n";
                timeout_amount++;
                if (timeout_amount > 15)
                {
                    fprintf(stderr, "Error: Server not responding...ending program\n");
                    close(sockfd);
                    exit(EXIT_FAILURE);
                }
                continue;
            }
            else
            {
                fprintf(stderr, "Error: Could not receive from client\n");
                close(sockfd);
                exit(EXIT_FAILURE);
            }
        }

        timeout_amount = 0;

        uint8_t packet_type = packet.type();
        uint8_t seq_num = packet.sequence();
        uint16_t checksum = packet.checksum();
        uint16_t data_size = packet.size();
        char* data = packet.data();
        cur_seq = (int) seq_num;

        send_ack = false;
        send_nak = false;

        // Switch behavior based on packet type
        switch(packet_type) {
            case ACK:
                std::cout << "ACKNOWLEDGE: Packet discarded" << std::endl << std::endl;
            break;
            case NAK:
                std::cout << "NOT ACKNOWLEDGE: Packet discarded" << std::endl << std::endl;
            break;
            case GET:
                std::cout << "GET: Packet discarded" << std::endl << std::endl;
            break;
            break;
            break;
            case TRN:
                if(exp_seq == cur_seq) {
                    if(checksum == calc_checksum(packet)) {
                        if(data_size > 0)
                        {
                            std::cout << "RECEIVED: sequence " << (int)cur_seq << "\n";
                            std::cout << "DATA:\n\n";
                            std::cout << packet_string(packet, 48) << "\n\n";
                            fwrite(data, 1, data_size, outfile);
                            //Updating the expected sequence number.
                            exp_seq = (exp_seq + 1) % SEQ_NUM;
                        }
                        else
                        {
                            fclose(outfile);
                            exp_seq = (exp_seq + 1) % SEQ_NUM;
                            std::cout << "RECEIVED: close packet for file transfer: closing transfer" 
                                << std::endl << std::endl;
                            running = false;
                            send_ack = true;
                            break;
                        }
                        send_ack = true;
                    }
                    else {
                        std::cout << "DAMAGED: sequence " << (int)cur_seq << ": damaged packet"
                            << std::endl << std::endl;
                        send_nak = true;
                    }
                }
                else {
                    std::cout << "OUT OF ORDER: sequence " << (int)cur_seq << ": incorrect sequence number" 
                        << std::endl << std::endl;
                    send_ack = true;
                }
            break;
            default:
                printf("UNKNOWN PACKET TYPE: Packet discarded");
            break;
        }

        // Send ACK for received packet
        if(send_ack) {
            packet = Packet(exp_seq, ACK);
            std::cout << "SENDING ACK: sequence " << (int)exp_seq << std::endl << std::endl;
        
            if (sendto(sockfd, packet.buffer, PACKET_SIZE, 0, (struct sockaddr*) &server, slen) == -1)
            {
                perror("Error: could not send acknowledge to server\n");
                close(sockfd);
                exit(EXIT_FAILURE);
            }
        }
        // Send NAK for damaged packet
        else if (send_nak) {
            packet = Packet(exp_seq, NAK);            
            std::cout << "SENDING NAK: sequence " << (int)exp_seq << std::endl << std::endl;
        
            if (sendto(sockfd, packet.buffer, PACKET_SIZE, 0, (struct sockaddr*) &server, slen) == -1)
            {
                perror("Error: could not send acknowledge to server\n");
                close(sockfd);
                exit(EXIT_FAILURE);
            }
        }

    }
    // Sending success message for completion
    char* msg = SUCCESS_MSG;
    std::string ttemp(SUCCESS_MSG);
    packet = Packet(msg, ttemp.size(), 0, GET);
    std::cout << "SENDING SUCCESS MSG" << std::endl;
    if (sendto(sockfd, packet.buffer, PACKET_SIZE, 0, (struct sockaddr*) &server, slen) == -1)
    {
        perror("Error: could not send acknowledge to server\n");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x448, %rsp            # imm = 0x448
movq %rsi, %r13
movl %edi, %ebx
leaq -0x70(%rbp), %r14
movq %rdx, (%r14)
movq %rcx, 0x8(%r14)
leaq -0x30(%rbp), %rax
movl $0x10, (%rax)
leaq -0x270(%rbp), %r12
movq %r12, %rdi
callq 0x3178
leaq 0x17cc(%rip), %rsi      # 0x415e
movq %r13, %rdi
callq 0x2190
movq %rax, -0x60(%rbp)
movl $0x0, -0x2c(%rbp)
movq 0x361c(%rip), %r13      # 0x5fc8
xorl %r15d, %r15d
movl $0x200, %edx            # imm = 0x200
movl %ebx, %edi
movq %r12, %rsi
xorl %ecx, %ecx
movq %r14, %r8
leaq -0x30(%rbp), %r9
callq 0x2100
cmpq $-0x1, %rax
je 0x29ed
movzbl -0x270(%rbp), %eax
cmpq $0x3, %rax
jbe 0x2a23
xorl %r15d, %r15d
leaq 0x18dd(%rip), %rdi      # 0x42c1
xorl %eax, %eax
callq 0x2050
jmp 0x29af
callq 0x2040
cmpl $0xb, (%rax)
jne 0x3047
movl $0x0, (%rax)
movl $0x23, %edx
movq %r13, %rdi
leaq 0x1751(%rip), %rsi      # 0x4161
callq 0x2180
incl %r15d
cmpl $0x10, %r15d
jne 0x29af
jmp 0x304e
leaq 0x15da(%rip), %rcx      # 0x4004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x1d, %edx
movq %r13, %rdi
leaq 0x179c(%rip), %rsi      # 0x41de
jmp 0x2a64
movl $0x15, %edx
movq %r13, %rdi
leaq 0x17a9(%rip), %rsi      # 0x41fc
jmp 0x2a64
movl $0x21, %edx
movq %r13, %rdi
leaq 0x1776(%rip), %rsi      # 0x41da
callq 0x2180
movq (%r13), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
jmp 0x29ac
movzbl -0x26f(%rbp), %r15d
cmpl %r15d, -0x2c(%rbp)
jne 0x2c1e
movzwl -0x26e(%rbp), %r15d
movzwl -0x26c(%rbp), %eax
movq %rax, -0x38(%rbp)
movq %r12, %rdi
callq 0x325e
cmpl %r15d, %eax
jne 0x2d71
movq -0x38(%rbp), %rax
testq %rax, %rax
je 0x2ec4
movl $0x13, %edx
movq %r13, %rdi
leaq 0x1700(%rip), %rsi      # 0x4212
callq 0x2180
movq %r13, %rdi
movl -0x2c(%rbp), %esi
callq 0x21f0
movl $0x1, %edx
movq %rax, %rdi
leaq 0x1652(%rip), %rsi      # 0x4183
callq 0x2180
movl $0x7, %edx
movq %r13, %rdi
leaq 0x16e1(%rip), %rsi      # 0x4226
callq 0x2180
movzwl -0x26c(%rbp), %eax
cmpw $0x30, %ax
movl $0x30, %ecx
cmovael %ecx, %eax
movzwl %ax, %r15d
movl $0x200, %edx            # imm = 0x200
leaq -0x470(%rbp), %rdi
xorl %esi, %esi
callq 0x20c0
leaq -0x470(%rbp), %rdi
leaq -0x26a(%rbp), %rsi
movq %r15, %rdx
callq 0x2110
leaq -0x48(%rbp), %r15
movq %r15, -0x58(%rbp)
leaq -0x470(%rbp), %r15
movq %r15, %rdi
callq 0x20a0
leaq (%rax,%rbp), %rdx
addq $-0x470, %rdx           # imm = 0xFB90
leaq -0x58(%rbp), %rdi
movq %r15, %rsi
callq 0x30da
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
movq %r13, %rdi
callq 0x2180
movl $0x2, %edx
movq %rax, %rdi
leaq 0x15ab(%rip), %rsi      # 0x4182
callq 0x2180
movq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %rax
cmpq %rax, %rdi
je 0x2bf5
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2170
movl $0x1, %esi
leaq -0x26a(%rbp), %rdi
movq -0x38(%rbp), %rdx
movq -0x60(%rbp), %rcx
callq 0x2230
movl -0x2c(%rbp), %eax
incl %eax
andl $0x1f, %eax
movl %eax, -0x2c(%rbp)
jmp 0x2ca5
movl $0x17, %edx
movq %r13, %rdi
leaq 0x1660(%rip), %rsi      # 0x428d
callq 0x2180
movq %r13, %rdi
movl %r15d, %esi
callq 0x21f0
movq %rax, %r15
movl $0x1b, %edx
movq %rax, %rdi
leaq 0x1656(%rip), %rsi      # 0x42a5
callq 0x2180
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movb $0x1, %al
movl %eax, -0x38(%rbp)
movl -0x2c(%rbp), %r15d
movzbl %r15b, %esi
leaq -0x470(%rbp), %rdi
xorl %edx, %edx
callq 0x317e
movl $0x200, %edx            # imm = 0x200
movq %r12, %rdi
leaq -0x470(%rbp), %rsi
callq 0x2110
movl $0x16, %edx
movq %r13, %rdi
leaq 0x1604(%rip), %rsi      # 0x42e7
callq 0x2180
movq %r13, %rdi
movl %r15d, %esi
callq 0x21f0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movl -0x30(%rbp), %r9d
movl $0x200, %edx            # imm = 0x200
movl %ebx, %edi
movq %r12, %rsi
xorl %ecx, %ecx
movq %r14, %r8
callq 0x2060
cmpq $-0x1, %rax
movl -0x38(%rbp), %ecx
jne 0x2eb7
jmp 0x3055
movl $0x12, %edx
movq %r13, %rdi
leaq 0x14e9(%rip), %rsi      # 0x4269
callq 0x2180
movq %r13, %rdi
movl -0x2c(%rbp), %esi
callq 0x21f0
movq %rax, %r15
movl $0x10, %edx
movq %rax, %rdi
leaq 0x14da(%rip), %rsi      # 0x427c
callq 0x2180
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movzbl -0x2c(%rbp), %esi
leaq -0x470(%rbp), %r15
movq %r15, %rdi
movl $0x1, %edx
callq 0x317e
movl $0x200, %edx            # imm = 0x200
movq %r12, %rdi
movq %r15, %rsi
callq 0x2110
movl $0x16, %edx
movq %r13, %rdi
leaq 0x14fc(%rip), %rsi      # 0x432b
callq 0x2180
movq %r13, %rdi
movl -0x2c(%rbp), %esi
callq 0x21f0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movl -0x30(%rbp), %r9d
movl $0x200, %edx            # imm = 0x200
movl %ebx, %edi
movq %r12, %rsi
xorl %ecx, %ecx
movq %r14, %r8
callq 0x2060
movb $0x1, %cl
cmpq $-0x1, %rax
je 0x305c
testb %cl, %cl
jne 0x29ac
jmp 0x2f4a
movq -0x60(%rbp), %rdi
callq 0x2160
movl -0x2c(%rbp), %eax
incl %eax
andl $0x1f, %eax
movl %eax, -0x2c(%rbp)
movl $0x3a, %edx
movq %r13, %rdi
leaq 0x1347(%rip), %rsi      # 0x422e
callq 0x2180
movq (%r13), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r15, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movl $0x0, -0x38(%rbp)
jmp 0x2caa
leaq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %r15
movq %r15, (%rdi)
leaq 0x13e6(%rip), %rsi      # 0x4342
leaq 0x13f5(%rip), %rdx      # 0x4358
callq 0x30da
movzwl -0x50(%rbp), %edx
leaq 0x13cf(%rip), %rsi      # 0x4342
leaq -0x470(%rbp), %rdi
xorl %ecx, %ecx
movl $0x2, %r8d
callq 0x31da
leaq -0x270(%rbp), %rdi
leaq -0x470(%rbp), %rsi
movl $0x200, %edx            # imm = 0x200
callq 0x2110
movq 0x3022(%rip), %r14      # 0x5fc8
leaq 0x13ac(%rip), %rsi      # 0x4359
movl $0x13, %edx
movq %r14, %rdi
callq 0x2180
movq (%r14), %rax
addq -0x18(%rax), %r14
movq %r14, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq 0x2ff0(%rip), %rdi      # 0x5fc8
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movl -0x30(%rbp), %r9d
leaq -0x270(%rbp), %rsi
leaq -0x70(%rbp), %r8
movl $0x200, %edx            # imm = 0x200
movl %ebx, %edi
xorl %ecx, %ecx
callq 0x2060
cmpq $-0x1, %rax
je 0x302f
movq -0x58(%rbp), %rdi
cmpq %r15, %rdi
je 0x301d
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2170
addq $0x448, %rsp            # imm = 0x448
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x12c8(%rip), %rdi      # 0x42fe
callq 0x2120
movl %ebx, %edi
callq 0x2240
callq 0x22a6
movl %ebx, %edi
callq 0x22d5
movl %ebx, %edi
callq 0x2308
movl %ebx, %edi
callq 0x22b2
movl %ebx, %edi
callq 0x2283
jmp 0x307c
movq %rax, %rbx
jmp 0x3094
movq %rax, %rbx
movq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %rax
cmpq %rax, %rdi
jne 0x3088
jmp 0x3094
movq %rax, %rbx
movq -0x58(%rbp), %rdi
cmpq %r15, %rdi
je 0x3094
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2170
movq %rbx, %rdi
callq 0x2200