// File: /workspace/github_c_makefile_star2_O3/sprt[P]lossless-transport/src/receiver.c
// Function: main_loop
void main_loop(void) {
	log_msg("---------- Waiting for a packet...\n");
	log_msg("Window: [%zu, %zu], buffer: %zu/%zu\n", window_start(w),
		window_end(w), window_buffer_size(w), window_get_size(w));

	/* Read the datagram received into a buffer */
	char buf[MAX_PACKET_SIZE];
	int len = recv(sockfd, buf, MAX_PACKET_SIZE, 0);
	if (len == -1) {
		exit_perror("recv");
	}

	/* Decode the datagram into a packet */
	pkt_t *pkt = pkt_new();
	if (pkt == NULL) {
		exit_msg("Could not allocate packet\n");
	}

	pkt_status_code decerr = pkt_decode(buf, len, pkt);
	if (decerr != PKT_OK) {
		log_msg("Error decoding packet (%s), ignoring\n", pkt_code_to_str(decerr));
		pkt_del(pkt);
		return;
	}

	log_msg("< %s\n", pkt_repr(pkt));

	if (!window_has(w, pkt_get_seqnum(pkt))) {
		log_msg("Out of window, ignoring\n");
		pkt_del(pkt);
		return;
	}

	/* We're gonna send a (N)ACK so let's allocate a new packet to reply */
	pkt_t *reply = pkt_new();
	if (reply == NULL) {
		exit_msg("Could not allocate reply packet\n");
	}

	if (pkt_get_tr(pkt)) {
		/* Send a NACK if we receive a truncated packet */
		pkt_status_code err = PKT_OK;
		err = err || pkt_set_type(reply, PTYPE_NACK);
		/* We don't store truncated packets so the window size doesn't change */
		err = err || pkt_set_window(reply, window_available(w));
		err = err || pkt_set_seqnum(reply, pkt_get_seqnum(pkt));

		if (err != PKT_OK) {
			exit_msg("Could not create packet: %s\n",
				pkt_code_to_str(err));
		}

		if (send_packet(sockfd, reply) == -1) {
			exit_perror("Could not send NACK: send:");
		}

		pkt_del(pkt);
		log_msg("> %s\n", pkt_repr(reply));
	} else {
		/* We're gonna send an ACK, but first we store the received
		 * packet in the buffer, and then we try to write out packets to
		 * the file, so that we can reply with an accurate window size. */

		if (window_find_seqnum(w, pkt_get_seqnum(pkt)) != NULL) {
			log_msg("Already in buffer\n");
		} else {
			if (window_push(w, pkt) == -1) {
				if (window_full(w)) {
					log_msg("Buffer full, not adding\n");
					// pkt_del(pkt);
					// pkt_del(reply);
					// return;
				} else {
					exit_msg("Could not add packet to buffer\n");
				}
			} else {
				log_msg("%d\n", pkt_get_seqnum(pkt));
			}
		}

		/* Save the timestamp of the packet we just received in case
		 * it's immediately removed from the buffer and freed. */
		uint32_t ack_timestamp = pkt_get_timestamp(pkt);

		/* Find the next in-sequence packet. If it's not in the buffer,
		 * we can't acknowledge any packet. */
		pkt_t *next_pkt = window_find_seqnum(w, window_start(w));
		while (next_pkt != NULL) {
			/* Try to write the packet to the file. Iff this succeeds,
			 * we can pop it from the buffer and slide the window. */

			const char *payload = pkt_get_payload(next_pkt);
			size_t payload_len = pkt_get_length(next_pkt);

			if (fwrite(payload, sizeof (*payload), payload_len, outfile) < payload_len) {
				exit_msg("Error writing to file\n");
			}

			log_msg("Wrote packet #%d\n", pkt_get_seqnum(next_pkt));
			assert(window_pop_timestamp(w, pkt_get_timestamp(next_pkt)) == next_pkt);

			/* We don't store truncated packets in the buffer so no
			* need to check for that */
			if (pkt_get_length(next_pkt) == 0) {
				log_msg("Received EOF packet, ready to quit\n");
			} else {
				/* Don't slide the window when we receive the
				* EOF packet. Rationale: the ACK may get lost
				* and when the sender retransmits the EOF packet,
				* it would fall outside our window. */
				window_slide(w);
			}

			pkt_del(next_pkt);
			next_pkt = window_find_seqnum(w, window_start(w));
		}

		assert(fflush(outfile) == 0);

		/* There's no duplication so we can just send an ACK */

		pkt_status_code err = PKT_OK;
		err = err || pkt_set_type(reply, PTYPE_ACK);
		err = err || pkt_set_window(reply, window_available(w));
		err = err || pkt_set_seqnum(reply, window_start(w));
		err = err || pkt_set_timestamp(reply, ack_timestamp);

		if (err != PKT_OK) {
			exit_msg("Could not create packet: %s\n",
				pkt_code_to_str(err));
		}

		if (send_packet(sockfd, reply) == -1) {
			exit_perror("Could not send ACK: send:");
		}

		log_msg("> %s\n", pkt_repr(reply));

		log_msg("Window: [%zu, %zu], buffer: %zu/%zu\n", window_start(w),
			window_end(w), window_buffer_size(w), window_get_size(w));
	}

	pkt_del(reply);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x228, %rsp            # imm = 0x228
leaq 0xf00(%rip), %rdi       # 0x3204
xorl %eax, %eax
callq 0x1210
movq 0x4246(%rip), %rdi      # 0x6558
callq 0x1ebf
movq %rax, %rbx
movq 0x4237(%rip), %rdi      # 0x6558
callq 0x1ec4
movq %rax, %r14
movq 0x4228(%rip), %rdi      # 0x6558
callq 0x2000
movq %rax, %r15
movq 0x4219(%rip), %rdi      # 0x6558
callq 0x1f7d
leaq 0xedd(%rip), %rdi       # 0x3228
movq %rbx, %rsi
movq %r14, %rdx
movq %r15, %rcx
movq %rax, %r8
xorl %eax, %eax
callq 0x1210
movl 0x3dac(%rip), %edi      # 0x6110
leaq 0x10(%rsp), %rsi
movl $0x210, %edx            # imm = 0x210
xorl %ecx, %ecx
callq 0x1040
movq %rax, %rbx
cmpl $-0x1, %ebx
jne 0x2389
leaq 0xec9(%rip), %rdi       # 0x324d
callq 0x19ee
xorl %eax, %eax
callq 0x149c
movq %rax, %r14
testq %rax, %rax
jne 0x23a6
leaq 0xeb3(%rip), %rdi       # 0x3252
xorl %eax, %eax
callq 0x194c
movslq %ebx, %rsi
leaq 0x10(%rsp), %rdi
movq %r14, %rdx
callq 0x152d
testl %eax, %eax
je 0x23d7
movl %eax, %edi
callq 0x17d3
leaq 0xea5(%rip), %rdi       # 0x326d
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
jmp 0x24ed
movq %r14, %rdi
callq 0x1a5a
leaq 0xead(%rip), %rdi       # 0x3293
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
movq 0x4161(%rip), %rbx      # 0x6558
movq %r14, %rdi
callq 0x17f1
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1f22
testb %al, %al
je 0x24df
xorl %eax, %eax
callq 0x149c
movq %rax, %rbx
testq %rax, %rax
jne 0x242f
leaq 0xe8a(%rip), %rdi       # 0x32b2
xorl %eax, %eax
callq 0x194c
movq %r14, %rdi
callq 0x1688
testb %al, %al
je 0x250a
movq %rbx, %rdi
movl $0x3, %esi
callq 0x1812
testl %eax, %eax
jne 0x2482
movq 0x4101(%rip), %rdi      # 0x6558
callq 0x1ff1
movzbl %al, %esi
movq %rbx, %rdi
callq 0x184a
testl %eax, %eax
jne 0x2482
movq %r14, %rdi
callq 0x17f1
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1861
testl %eax, %eax
je 0x249d
movl $0x1, %edi
callq 0x17d3
leaq 0xe40(%rip), %rdi       # 0x32d3
movq %rax, %rsi
xorl %eax, %eax
callq 0x194c
movl 0x3c6d(%rip), %edi      # 0x6110
movq %rbx, %rsi
callq 0x1cf5
cmpl $-0x1, %eax
jne 0x24bc
leaq 0xe39(%rip), %rdi       # 0x32f0
callq 0x19ee
movq %r14, %rdi
callq 0x14ab
movq %rbx, %rdi
callq 0x1a5a
leaq 0xe38(%rip), %rdi       # 0x330b
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
jmp 0x24f0
leaq 0xdb3(%rip), %rdi       # 0x3299
xorl %eax, %eax
callq 0x1210
movq %r14, %rbx
movq %rbx, %rdi
callq 0x14ab
addq $0x228, %rsp            # imm = 0x228
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x4047(%rip), %r15      # 0x6558
movq %r14, %rdi
callq 0x17f1
movzbl %al, %esi
movq %r15, %rdi
callq 0x200e
testq %rax, %rax
je 0x2539
leaq 0xde1(%rip), %rdi       # 0x3311
xorl %eax, %eax
callq 0x1210
jmp 0x258f
movq 0x4018(%rip), %rdi      # 0x6558
movq %r14, %rsi
callq 0x1f82
cmpl $-0x1, %eax
je 0x2568
movq %r14, %rdi
callq 0x17f1
movzbl %al, %esi
leaq 0xc32(%rip), %rdi       # 0x3191
xorl %eax, %eax
callq 0x1210
jmp 0x258f
movq 0x3fe9(%rip), %rdi      # 0x6558
callq 0x1fdd
testb %al, %al
je 0x2581
leaq 0xda5(%rip), %rdi       # 0x3324
jmp 0x2530
leaq 0xdb5(%rip), %rdi       # 0x333d
xorl %eax, %eax
callq 0x194c
movq %r14, %rdi
callq 0x17f5
movl %eax, 0xc(%rsp)
movq 0x3fb6(%rip), %r14      # 0x6558
movq %r14, %rdi
callq 0x1ebf
movq %r14, %rdi
movq %rax, %rsi
callq 0x200e
testq %rax, %rax
je 0x269a
movq %rax, %r13
leaq 0xd95(%rip), %r14       # 0x335d
leaq 0xda5(%rip), %r15       # 0x3374
movq %r13, %rdi
callq 0x17fb
movq %rax, %rbp
movq %r13, %rdi
callq 0x151c
movzwl %ax, %r12d
movq 0x3f73(%rip), %rcx      # 0x6560
movl $0x1, %esi
movq %rbp, %rdi
movq %r12, %rdx
callq 0x11b0
cmpq %r12, %rax
jae 0x260c
movq %r14, %rdi
xorl %eax, %eax
callq 0x194c
movq %r13, %rdi
callq 0x17f1
movzbl %al, %esi
movq %r15, %rdi
xorl %eax, %eax
callq 0x1210
movq 0x3f30(%rip), %r12      # 0x6558
movq %r13, %rdi
callq 0x17f5
movq %r12, %rdi
movl %eax, %esi
callq 0x20c8
cmpq %r13, %rax
jne 0x27b0
movq %r13, %rdi
callq 0x151c
testw %ax, %ax
je 0x265e
movq 0x3f01(%rip), %rdi      # 0x6558
callq 0x1ee1
jmp 0x266c
leaq 0xd86(%rip), %rdi       # 0x33eb
xorl %eax, %eax
callq 0x1210
movq %r13, %rdi
callq 0x14ab
movq 0x3edd(%rip), %r12      # 0x6558
movq %r12, %rdi
callq 0x1ebf
movq %r12, %rdi
movq %rax, %rsi
callq 0x200e
movq %rax, %r13
testq %rax, %rax
jne 0x25cf
movq 0x3ebf(%rip), %rdi      # 0x6560
callq 0x1100
testl %eax, %eax
jne 0x27cf
movq %rbx, %rdi
movl $0x2, %esi
callq 0x1812
testl %eax, %eax
jne 0x2705
movq 0x3e92(%rip), %rdi      # 0x6558
callq 0x1ff1
movzbl %al, %esi
movq %rbx, %rdi
callq 0x184a
testl %eax, %eax
jne 0x2705
movq 0x3e77(%rip), %rdi      # 0x6558
callq 0x1ebf
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1861
testl %eax, %eax
jne 0x2705
movq %rbx, %rdi
movl 0xc(%rsp), %esi
callq 0x18ab
testl %eax, %eax
je 0x2720
movl $0x1, %edi
callq 0x17d3
leaq 0xbbd(%rip), %rdi       # 0x32d3
movq %rax, %rsi
xorl %eax, %eax
callq 0x194c
movl 0x39ea(%rip), %edi      # 0x6110
movq %rbx, %rsi
callq 0x1cf5
cmpl $-0x1, %eax
jne 0x273f
leaq 0xcea(%rip), %rdi       # 0x3424
callq 0x19ee
movq %rbx, %rdi
callq 0x1a5a
leaq 0xbbd(%rip), %rdi       # 0x330b
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
movq 0x3df9(%rip), %rdi      # 0x6558
callq 0x1ebf
movq %rax, %r14
movq 0x3dea(%rip), %rdi      # 0x6558
callq 0x1ec4
movq %rax, %r15
movq 0x3ddb(%rip), %rdi      # 0x6558
callq 0x2000
movq %rax, %r12
movq 0x3dcc(%rip), %rdi      # 0x6558
callq 0x1f7d
leaq 0xa90(%rip), %rdi       # 0x3228
movq %r14, %rsi
movq %r15, %rdx
movq %r12, %rcx
movq %rax, %r8
xorl %eax, %eax
callq 0x1210
jmp 0x24f0
leaq 0xbcf(%rip), %rdi       # 0x3386
leaq 0xc09(%rip), %rsi       # 0x33c7
leaq 0xc11(%rip), %rcx       # 0x33d6
movl $0x92, %edx
callq 0x10b0
leaq 0xc39(%rip), %rdi       # 0x340f
leaq 0xbea(%rip), %rsi       # 0x33c7
leaq 0xbf2(%rip), %rcx       # 0x33d6
movl $0xa4, %edx
callq 0x10b0