// File: /workspace/github_c_makefile_star2_O1/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 0xf08(%rip), %rdi       # 0x3204
xorl %eax, %eax
callq 0x1210
movq 0x424e(%rip), %rdi      # 0x6558
callq 0x1eb3
movq %rax, %rbx
movq 0x423f(%rip), %rdi      # 0x6558
callq 0x1eb8
movq %rax, %r14
movq 0x4230(%rip), %rdi      # 0x6558
callq 0x1ff4
movq %rax, %r15
movq 0x4221(%rip), %rdi      # 0x6558
callq 0x1f71
leaq 0xee5(%rip), %rdi       # 0x3228
movq %rbx, %rsi
movq %r14, %rdx
movq %r15, %rcx
movq %rax, %r8
xorl %eax, %eax
callq 0x1210
movl 0x3db4(%rip), %edi      # 0x6110
leaq 0x10(%rsp), %rsi
movl $0x210, %edx            # imm = 0x210
xorl %ecx, %ecx
callq 0x1040
movq %rax, %rbx
cmpl $-0x1, %ebx
jne 0x2381
leaq 0xed1(%rip), %rdi       # 0x324d
callq 0x19da
xorl %eax, %eax
callq 0x149c
movq %rax, %r14
testq %rax, %rax
jne 0x239e
leaq 0xebb(%rip), %rdi       # 0x3252
xorl %eax, %eax
callq 0x1938
movslq %ebx, %rsi
leaq 0x10(%rsp), %rdi
movq %r14, %rdx
callq 0x152a
testl %eax, %eax
je 0x23cf
movl %eax, %edi
callq 0x17b6
leaq 0xead(%rip), %rdi       # 0x326d
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
jmp 0x24ee
movq %r14, %rdi
callq 0x1a46
leaq 0xeb5(%rip), %rdi       # 0x3293
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
movq 0x4169(%rip), %rbx      # 0x6558
movq %r14, %rdi
callq 0x17d4
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1f16
testb %al, %al
je 0x24e0
xorl %eax, %eax
callq 0x149c
movq %rax, %rbx
testq %rax, %rax
jne 0x2427
leaq 0xe92(%rip), %rdi       # 0x32b2
xorl %eax, %eax
callq 0x1938
movq %r14, %rdi
callq 0x166e
testb %al, %al
je 0x250b
movq %rbx, %rdi
movl $0x3, %esi
callq 0x17fa
movb $0x1, %bpl
testl %eax, %eax
jne 0x247f
movq 0x4106(%rip), %rdi      # 0x6558
callq 0x1fe5
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1832
testl %eax, %eax
jne 0x247f
movq %r14, %rdi
callq 0x17d4
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1849
testl %eax, %eax
setne %bpl
testb %bpl, %bpl
je 0x249e
movzbl %bpl, %edi
callq 0x17b6
leaq 0xe3f(%rip), %rdi       # 0x32d3
movq %rax, %rsi
xorl %eax, %eax
callq 0x1938
movl 0x3c6c(%rip), %edi      # 0x6110
movq %rbx, %rsi
callq 0x1ce1
cmpl $-0x1, %eax
jne 0x24bd
leaq 0xe38(%rip), %rdi       # 0x32f0
callq 0x19da
movq %r14, %rdi
callq 0x14ab
movq %rbx, %rdi
callq 0x1a46
leaq 0xe37(%rip), %rdi       # 0x330b
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
jmp 0x24f1
leaq 0xdb2(%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 0x4046(%rip), %r15      # 0x6558
movq %r14, %rdi
callq 0x17d4
movzbl %al, %esi
movq %r15, %rdi
callq 0x2002
testq %rax, %rax
je 0x253a
leaq 0xde0(%rip), %rdi       # 0x3311
xorl %eax, %eax
callq 0x1210
jmp 0x2590
movq 0x4017(%rip), %rdi      # 0x6558
movq %r14, %rsi
callq 0x1f76
cmpl $-0x1, %eax
je 0x2569
movq %r14, %rdi
callq 0x17d4
movzbl %al, %esi
leaq 0xc31(%rip), %rdi       # 0x3191
xorl %eax, %eax
callq 0x1210
jmp 0x2590
movq 0x3fe8(%rip), %rdi      # 0x6558
callq 0x1fd1
testb %al, %al
je 0x2582
leaq 0xda4(%rip), %rdi       # 0x3324
jmp 0x2531
leaq 0xdb4(%rip), %rdi       # 0x333d
xorl %eax, %eax
callq 0x1938
movq %r14, %rdi
callq 0x17d8
movl %eax, 0xc(%rsp)
movq 0x3fb5(%rip), %r14      # 0x6558
movq %r14, %rdi
callq 0x1eb3
movq %r14, %rdi
movq %rax, %rsi
callq 0x2002
testq %rax, %rax
je 0x269b
movq %rax, %r13
leaq 0xd94(%rip), %r14       # 0x335d
leaq 0xda4(%rip), %r15       # 0x3374
movq %r13, %rdi
callq 0x17de
movq %rax, %rbp
movq %r13, %rdi
callq 0x1519
movzwl %ax, %r12d
movq 0x3f72(%rip), %rcx      # 0x6560
movl $0x1, %esi
movq %rbp, %rdi
movq %r12, %rdx
callq 0x11b0
cmpq %r12, %rax
jae 0x260d
movq %r14, %rdi
xorl %eax, %eax
callq 0x1938
movq %r13, %rdi
callq 0x17d4
movzbl %al, %esi
movq %r15, %rdi
xorl %eax, %eax
callq 0x1210
movq 0x3f2f(%rip), %r12      # 0x6558
movq %r13, %rdi
callq 0x17d8
movq %r12, %rdi
movl %eax, %esi
callq 0x20bc
cmpq %r13, %rax
jne 0x27ba
movq %r13, %rdi
callq 0x1519
testw %ax, %ax
je 0x265f
movq 0x3f00(%rip), %rdi      # 0x6558
callq 0x1ed5
jmp 0x266d
leaq 0xd85(%rip), %rdi       # 0x33eb
xorl %eax, %eax
callq 0x1210
movq %r13, %rdi
callq 0x14ab
movq 0x3edc(%rip), %r12      # 0x6558
movq %r12, %rdi
callq 0x1eb3
movq %r12, %rdi
movq %rax, %rsi
callq 0x2002
movq %rax, %r13
testq %rax, %rax
jne 0x25d0
movq 0x3ebe(%rip), %rdi      # 0x6560
callq 0x1100
testl %eax, %eax
jne 0x27d9
movq %rbx, %rdi
movl $0x2, %esi
callq 0x17fa
movb $0x1, %bpl
testl %eax, %eax
jne 0x270b
movq 0x3e8e(%rip), %rdi      # 0x6558
callq 0x1fe5
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1832
testl %eax, %eax
jne 0x270b
movq 0x3e73(%rip), %rdi      # 0x6558
callq 0x1eb3
movzbl %al, %esi
movq %rbx, %rdi
callq 0x1849
testl %eax, %eax
jne 0x270b
movq %rbx, %rdi
movl 0xc(%rsp), %esi
callq 0x1893
testl %eax, %eax
setne %bpl
testb %bpl, %bpl
je 0x272a
movzbl %bpl, %edi
callq 0x17b6
leaq 0xbb3(%rip), %rdi       # 0x32d3
movq %rax, %rsi
xorl %eax, %eax
callq 0x1938
movl 0x39e0(%rip), %edi      # 0x6110
movq %rbx, %rsi
callq 0x1ce1
cmpl $-0x1, %eax
jne 0x2749
leaq 0xce0(%rip), %rdi       # 0x3424
callq 0x19da
movq %rbx, %rdi
callq 0x1a46
leaq 0xbb3(%rip), %rdi       # 0x330b
movq %rax, %rsi
xorl %eax, %eax
callq 0x1210
movq 0x3def(%rip), %rdi      # 0x6558
callq 0x1eb3
movq %rax, %r14
movq 0x3de0(%rip), %rdi      # 0x6558
callq 0x1eb8
movq %rax, %r15
movq 0x3dd1(%rip), %rdi      # 0x6558
callq 0x1ff4
movq %rax, %r12
movq 0x3dc2(%rip), %rdi      # 0x6558
callq 0x1f71
leaq 0xa86(%rip), %rdi       # 0x3228
movq %r14, %rsi
movq %r15, %rdx
movq %r12, %rcx
movq %rax, %r8
xorl %eax, %eax
callq 0x1210
jmp 0x24f1
leaq 0xbc5(%rip), %rdi       # 0x3386
leaq 0xbff(%rip), %rsi       # 0x33c7
leaq 0xc07(%rip), %rcx       # 0x33d6
movl $0x92, %edx
callq 0x10b0
leaq 0xc2f(%rip), %rdi       # 0x340f
leaq 0xbe0(%rip), %rsi       # 0x33c7
leaq 0xbe8(%rip), %rcx       # 0x33d6
movl $0xa4, %edx
callq 0x10b0