// File: /workspace/github_cpp_makefile_star2_O1/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 $0x458, %rsp            # imm = 0x458
movq %rsi, %r13
movl %edi, %ebx
leaq -0x78(%rbp), %r14
movq %rdx, (%r14)
movq %rcx, 0x8(%r14)
leaq -0x30(%rbp), %rax
movl $0x10, (%rax)
leaq -0x278(%rbp), %r12
movq %r12, %rdi
callq 0x31b8
leaq 0x17cc(%rip), %rsi      # 0x415e
movq %r13, %rdi
callq 0x2190
movq %rax, -0x60(%rbp)
movb $0x1, %al
movl %eax, -0x38(%rbp)
movl $0x0, -0x2c(%rbp)
movq 0x3617(%rip), %r13      # 0x5fc8
movl $0x10, %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
jne 0x2a07
callq 0x2040
cmpl $0xb, (%rax)
jne 0x3088
movl $0x0, (%rax)
movl $0x23, %edx
movq %r13, %rdi
leaq 0x1769(%rip), %rsi      # 0x4161
callq 0x2180
decl %r15d
jne 0x29b7
jmp 0x308f
movzbl -0x278(%rbp), %eax
cmpq $0x3, %rax
ja 0x2c24
leaq 0x15e5(%rip), %rcx      # 0x4004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x1d, %edx
movq %r13, %rdi
leaq 0x17a7(%rip), %rsi      # 0x41de
jmp 0x2bc5
movl $0x15, %edx
movq %r13, %rdi
leaq 0x17b1(%rip), %rsi      # 0x41fc
jmp 0x2bc5
movzbl -0x277(%rbp), %r15d
cmpl %r15d, -0x2c(%rbp)
jne 0x2c3a
movl %r15d, -0x34(%rbp)
movzwl -0x276(%rbp), %r15d
movzwl -0x274(%rbp), %eax
movq %rax, -0x68(%rbp)
movq %r12, %rdi
callq 0x329a
cmpl %r15d, %eax
jne 0x2ccb
movq -0x68(%rbp), %rax
testq %rax, %rax
movl -0x34(%rbp), %r15d
je 0x2f03
movl $0x13, %edx
movq %r13, %rdi
leaq 0x1768(%rip), %rsi      # 0x4212
callq 0x2180
movq %r13, %rdi
movl %r15d, %esi
callq 0x21f0
movl $0x1, %edx
movq %rax, %rdi
leaq 0x16ba(%rip), %rsi      # 0x4183
callq 0x2180
movl $0x7, %edx
movq %r13, %rdi
leaq 0x1749(%rip), %rsi      # 0x4226
callq 0x2180
movzwl -0x274(%rbp), %eax
cmpw $0x30, %ax
movl $0x30, %ecx
cmovael %ecx, %eax
movzwl %ax, %r15d
movl $0x200, %edx            # imm = 0x200
leaq -0x480(%rbp), %rdi
xorl %esi, %esi
callq 0x20c0
leaq -0x480(%rbp), %rdi
leaq -0x272(%rbp), %rsi
movq %r15, %rdx
callq 0x2110
leaq -0x48(%rbp), %r15
movq %r15, -0x58(%rbp)
leaq -0x480(%rbp), %r15
movq %r15, %rdi
callq 0x20a0
leaq (%rax,%rbp), %rdx
addq $-0x480, %rdx           # imm = 0xFB80
leaq -0x58(%rbp), %rdi
movq %r15, %rsi
callq 0x311c
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
movq %r13, %rdi
callq 0x2180
movl $0x2, %edx
movq %rax, %rdi
leaq 0x1613(%rip), %rsi      # 0x4182
callq 0x2180
movq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %rax
cmpq %rax, %rdi
je 0x2b8d
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2170
movl $0x1, %esi
leaq -0x272(%rbp), %rdi
movq -0x68(%rbp), %rdx
movq -0x60(%rbp), %rcx
callq 0x2230
movl -0x2c(%rbp), %eax
incl %eax
andl $0x1f, %eax
movl %eax, -0x2c(%rbp)
jmp 0x2cc1
movl $0x21, %edx
movq %r13, %rdi
leaq 0x1615(%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
xorl %r15d, %r15d
jmp 0x2d55
xorl %r15d, %r15d
leaq 0x1693(%rip), %rdi      # 0x42c1
xorl %eax, %eax
callq 0x2050
jmp 0x2d55
movl $0x17, %edx
movq %r13, %rdi
leaq 0x1644(%rip), %rsi      # 0x428d
callq 0x2180
movq %r13, %rdi
movl %r15d, %esi
callq 0x21f0
movq %rax, %r15
movl $0x1b, %edx
movq %rax, %rdi
leaq 0x163a(%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
xorl %r15d, %r15d
jmp 0x2d57
movl $0x12, %edx
movq %r13, %rdi
leaq 0x158f(%rip), %rsi      # 0x4269
callq 0x2180
movq %r13, %rdi
movl -0x34(%rbp), %esi
callq 0x21f0
movq %rax, %r15
movl $0x10, %edx
movq %rax, %rdi
leaq 0x1580(%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
movb $0x1, %r15b
xorl %eax, %eax
testb %al, %al
je 0x2e26
movl -0x2c(%rbp), %r15d
movzbl %r15b, %esi
leaq -0x480(%rbp), %r14
movq %r14, %rdi
xorl %edx, %edx
callq 0x31be
movl $0x200, %edx            # imm = 0x200
movq %r12, %rdi
movq %r14, %rsi
leaq -0x78(%rbp), %r14
callq 0x2110
movl $0x16, %edx
movq %r13, %rdi
leaq 0x154c(%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
jne 0x2ef4
jmp 0x3096
testb %r15b, %r15b
je 0x2ef4
movl -0x2c(%rbp), %r15d
movzbl %r15b, %esi
leaq -0x480(%rbp), %r14
movq %r14, %rdi
movl $0x1, %edx
callq 0x31be
movl $0x200, %edx            # imm = 0x200
movq %r12, %rdi
movq %r14, %rsi
leaq -0x78(%rbp), %r14
callq 0x2110
movl $0x16, %edx
movq %r13, %rdi
leaq 0x14bd(%rip), %rsi      # 0x432b
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
je 0x309d
testb $0x1, -0x38(%rbp)
jne 0x29b1
jmp 0x2f8b
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 0x1308(%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
movb $0x1, %al
movl $0x0, -0x38(%rbp)
jmp 0x2cc3
leaq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %r15
movq %r15, (%rdi)
leaq 0x13a5(%rip), %rsi      # 0x4342
leaq 0x13b4(%rip), %rdx      # 0x4358
callq 0x311c
movzwl -0x50(%rbp), %edx
leaq 0x138e(%rip), %rsi      # 0x4342
leaq -0x480(%rbp), %rdi
xorl %ecx, %ecx
movl $0x2, %r8d
callq 0x3216
leaq -0x278(%rbp), %rdi
leaq -0x480(%rbp), %rsi
movl $0x200, %edx            # imm = 0x200
callq 0x2110
movq 0x2fe1(%rip), %r14      # 0x5fc8
leaq 0x136b(%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 0x2faf(%rip), %rdi      # 0x5fc8
callq 0x2030
movq %rax, %rdi
callq 0x20d0
movl -0x30(%rbp), %r9d
leaq -0x278(%rbp), %rsi
leaq -0x78(%rbp), %r8
movl $0x200, %edx            # imm = 0x200
movl %ebx, %edi
xorl %ecx, %ecx
callq 0x2060
cmpq $-0x1, %rax
je 0x3070
movq -0x58(%rbp), %rdi
cmpq %r15, %rdi
je 0x305e
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2170
addq $0x458, %rsp            # imm = 0x458
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x1287(%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 0x30bd
movq %rax, %rbx
jmp 0x30d5
movq %rax, %rbx
movq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %rax
cmpq %rax, %rdi
jne 0x30c9
jmp 0x30d5
movq %rax, %rbx
movq -0x58(%rbp), %rdi
cmpq %r15, %rdi
je 0x30d5
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2170
movq %rbx, %rdi
callq 0x2200
nop