Beispiel #1
0
int main(int argc, char *argv[])
{
    int sockfd;
    int portno, n_char;
    int slen;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char *hostname, *filepath;

    double p_loss, p_corrupt;
    p_loss = 0.0;
    p_corrupt = 0.0;

    int expect_seq_num;
    struct packet snd_pkt, rcv_pkt;

    FILE* file;

    if (argc < 4)
    {
        fprintf(stderr, "Usage: %s hostname port filepath [loss ratio] [corrupt ratio]\n", argv[0]);
        exit(0);
    }

    switch (argc)
    {
        case 6:
            p_corrupt = atof(argv[5]);
        case 5:
            p_loss = atof(argv[4]);
        default:
            filepath = argv[3];
            portno = atoi(argv[2]);
            hostname = argv[1];
            break;
    }

    sockfd = socket(AF_INET, SOCK_DGRAM, 0); // Using UDP!

    if (sockfd < 0)
    {
        error("Error opening socket");
    }

    server = gethostbyname(hostname);
    if (server == NULL)
    {
        fprintf(stderr, "Error: no such host\n");
        exit(0);
    }

    bzero((char *)&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);

    // Create the initial packet
    expect_seq_num = 1;
    snd_pkt = make_packet();

    set_syn(&snd_pkt);
    snd_pkt.seq_num = 0;
    set_data(&snd_pkt, filepath, strlen(filepath));

    slen = sizeof(serv_addr);

    char str[100] = "copy_";

    char *dirc, *basec, *dname, *bname;
    dirc = strdup(filepath);
    basec = strdup(filepath);
    dname = dirname(dirc);
    bname = basename(basec);

    file = fopen(strcat(str, bname), "wb");

    // Send the initial packet
    msg("Sending file request to sender...\n");
    n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, slen);
    if (n_char < 0)
    {
        error("Error sending packet");
    }

    // Go-Back-N FSM
    while (1)
    {
        // Wait to receive a message
        // if (rcv_pkt)
        // {
        //     free(rcv_pkt);
        // }

        rcv_pkt = make_packet();

        n_char = recvfrom(sockfd, &rcv_pkt, sizeof(rcv_pkt), 0, (struct sockaddr*)&serv_addr, (socklen_t*)&slen);

        if (check_none(&rcv_pkt))
        {
            msg("No such file exists on the sender side\n");
            fclose(file);
            remove(str);
            teardown(NULL, sockfd);
        }

        if (check_fin(&rcv_pkt)) // server closing connection
        {
            msg("-> FIN\n");
            msg("<- FIN-ACK ...\n");

            //free(&snd_pkt);
            snd_pkt = make_packet();
            set_fin(&snd_pkt);

            n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
            if (n_char < 0)
            {
                error("Error sending FIN-ACK");
            }

            //free(&rcv_pkt);
            //free(&snd_pkt);
            teardown(file, sockfd);
            break;
        }

        if (n_char < 0)
        {
            msg("Packet from sender LOST\n");
        }
        else if (chance() < p_loss)
        {
            msg("Packet from sender LOST\n");
        }
        else if (chance() < p_corrupt)
        {
            msg("Packet from sender CORRUPT\n");
            
            msg("<- RE-ACK: SEQNUM %d ...\n", snd_pkt.seq_num);
            int n_char;
            n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

            if (n_char < 0)
            {
                error("Error acking packet\n");
            }
        }
        else if (rcv_pkt.seq_num == expect_seq_num)
        {
            msg("-> DATA: SEQNUM %d\n", rcv_pkt.seq_num);

            fwrite(rcv_pkt.data, 1, rcv_pkt.d_length, file);
            expect_seq_num++;

            //free(&snd_pkt);
            snd_pkt = make_packet();
            set_ack(&snd_pkt);
            snd_pkt.seq_num = rcv_pkt.seq_num;

            send_ack(sockfd, snd_pkt, serv_addr);
        }
        else if (rcv_pkt.seq_num < expect_seq_num)
        {
            msg("-> DATA: SEQNUM %d\n", rcv_pkt.seq_num);

            //free(&snd_pkt);
            snd_pkt = make_packet();
            set_ack(&snd_pkt);
            snd_pkt.seq_num = rcv_pkt.seq_num;

            msg("<- RE-ACK: SEQNUM %d ...\n", snd_pkt.seq_num);
            int n_char;
            n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

            if (n_char < 0)
            {
                error("Error acking packet\n");
            }
        }
        else
        {
            msg("-> DATA: SEQNUM %d\n", rcv_pkt.seq_num);
            
            msg("<- RE-ACK: SEQNUM %d ...\n", snd_pkt.seq_num);
            int n_char;
            n_char = sendto(sockfd, &snd_pkt, sizeof(snd_pkt), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

            if (n_char < 0)
            {
                error("Error acking packet\n");
            }
        }
    }
}
Beispiel #2
0
// return 1 on success, -1 if queue is_full, 0 for other failure
int ErrorControl::send(char ecPlayerId, void *dataPtr, long unsigned int dataLen)
{
	if( connecting_player_count == 0)
		return 1;

	if( send_queue_space() < MAX_QUEUE/2)
	{
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 1)
		DEBUG_LOG("ec_remote.send() fail, buffer half full");
#endif
		return -1;
	}

	int frameId = en_send_queue();
	if( frameId < 0)
	{
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 1)
		DEBUG_LOG("ec_remote.send() fail, buffer full");
#endif
		return frameId;
	}
	else
	{
		// -------- add buffer to queue --------- //
		err_when( frameId >= MAX_QUEUE );
		VLenQueue &sq = send_queue[frameId];
		sq.clear();
		char *ecMsg = sq.reserve( sizeof(EcMsgHeader) + dataLen + CRC_LEN );
		((EcMsgHeader *)ecMsg)->init( FIRST_SEND, self_ec_player_id, frameId );
		memcpy( ecMsg + sizeof(EcMsgHeader), dataPtr, dataLen );
		*((CRC_TYPE *) (ecMsg + sizeof(EcMsgHeader) + dataLen) ) = crc8((unsigned char *)ecMsg, sizeof(EcMsgHeader) + dataLen);

		// ------- clear all ack flags of that frame --------//
		PID_TYPE toDPid = BROADCAST_PID;
		clear_ack( frameId );
		if( ecPlayerId != 0)
		{
			toDPid = dp_id[ecPlayerId];
			err_when(toDPid == BROADCAST_PID);
			for(char p = 1; p <= MAX_PLAYER; ++p)
				if( p != ecPlayerId )
					set_ack(p, frameId);
		}

		// ------- try to send the data for the first time ------- //
		if( mp_ptr->send(toDPid, sq.queue_buf, sq.length()) )
		{
			// mark send time
			mark_send_time(frameId, TIME_OUT );

#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 3)
			debugStr = "ec_remote.send() successful, frame ";
			debugStr += frameId;
			DEBUG_LOG(debugStr);
#endif

			// mark the func_id of the message RE_SEND
			((EcMsgHeader *)ecMsg)->func_id = RE_SEND;

			// recalculate CRC
			*((CRC_TYPE *) (ecMsg + sizeof(EcMsgHeader) + dataLen) ) = crc8((unsigned char *)ecMsg, sizeof(EcMsgHeader) + dataLen);
		}
		else
		{
			// mark send time, mark a shorter time
			mark_send_time(frameId, SHORT_TIME_OUT);

#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2)
			debugStr = "ec_remote.send() fail, frame ";
			debugStr += frameId;
			DEBUG_LOG(debugStr);
#endif
			// still return true to sender, as it will be re-send later
		}
	}

	return 1;
}
int main(int argc, char **argv)
{
	int sock;
	struct sockaddr_in addr;
	char buffer[MAX_PACKET_SIZE];
	int recsize;
	int retval;

	socklen_t addr_len;


	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock == -1){
		fprintf(stderr, "Socket failed.\n");
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(UDP_PORT);

	retval = bind(sock,(struct sockaddr *)&addr, sizeof(addr));
	if(retval != 0){
		fprintf(stderr, "Socket bind failed.\n");
		close(sock);
		return -1;
	}

	struct common_header header;
	struct ack_packet ack;
	int packet_count = 0;

	/* Main loop to receive packets and send back Act.*/
	for(;;){
		recsize = recvfrom (sock, buffer, sizeof(buffer), 0,
						(struct sockaddr *)&addr, &addr_len);
		printf("recsize: %d\n", recsize);

		struct stream strm;
		strm.strm = buffer;
		strm.p = buffer;

		/* Read and analyze packet common header.*/
		read_header(&header, &strm);

        sleep(1);

        /*Send an Act Packet every 16 successive received packets. */
        if (++packet_count == 16){
        	set_ack(&ack); /* Set the ack contetns.*/

        	addr.sin_addr.s_addr = htonl(0x7F000001); /* send to address 127.0.0.1 */
        	addr.sin_port = htons(UDP_PORT);

        	int byte_sent = sendto(sock, &ack, sizeof(ack), 0,
            				(struct sockaddr *)&addr, addr_len);
        	if (byte_sent < 0)
        		fprintf(stderr, "Error sending Act Packet. \n");
        	addr.sin_addr.s_addr = INADDR_ANY; /* Set address back to recvfrom */
        	addr.sin_port = htons(UDP_PORT);

        	packet_count = 0;
        }
	}

}
Beispiel #4
0
void ErrorControl::yield()
{
	// -------- receive any frame from dplay -----------//
	char *recvPtr;
	uint32_t recvLen;
	PID_TYPE from;

	static int simError = 1;

	// check any player lost

	// ##### begin Gilbert 2/5 ########//
	int sysMsgCount;
	int p;

	// detect any player lost, detected previous mp_ptr->send
	for( p = 1; p <= MAX_PLAYER; ++p)
	{
		if( dp_id[p-1] && !mp_ptr->is_player_connecting(dp_id[p-1]) )
		{
			set_player_lost(p);
		}
	}

	while( (recvPtr = mp_ptr->receive(&from, &recvLen, &sysMsgCount)) != NULL
		|| sysMsgCount != 0)
	{
		// -------- detect any player lost ---------//

		if( sysMsgCount )
		{
			for( p = 1; p <= MAX_PLAYER; ++p)
			{
				if( dp_id[p-1] && !mp_ptr->is_player_connecting(dp_id[p-1]) )
				{
					set_player_lost(p);
				}
			}
		}

		if( !recvPtr )
			break;	// only received system message from direct play
	// ##### end Gilbert 2/5 ########//

		// -------- receive the message ----------//
#ifdef DEBUG
		// simulate crc error
//		if( ++simError >= 10)
//			simError = 0;
#endif
		if( simError && !crc8((unsigned char *)recvPtr, recvLen))
		{
			// crc correct
			EcMsgHeader ecMsg = *(EcMsgHeader *)recvPtr;
			switch( ecMsg.func_id )
			{
			case FIRST_SEND:
				// accept except frameId is wait_to_receive -1 or recv_flag is set
				if( is_waiting_receive( ecMsg.sender_id, ecMsg.frame_id ) )
				{
					err_when( ecMsg.sender_id <= 0 || ecMsg.sender_id > MAX_PLAYER);
#if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 3 )
					debugStr = "ec_remote : FIRST_SEND received, from:";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " accepted";
					DEBUG_LOG(debugStr);
#endif
					if( !is_recv_full() )
					{
						if( dp_id[ecMsg.sender_id-1] )
						{
							// mark recv_flag
							set_recv_flag(ecMsg.sender_id, ecMsg.frame_id);

							// send ACK
							char replyMsg[sizeof(EcMsgHeader) + CRC_LEN];
							((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id);
							*((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader));
							mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) );

							if( ecMsg.frame_id == wait_to_receive[ecMsg.sender_id-1] )
							{
								// clear recv_flag, until it is zero
								char &scanFrame = wait_to_receive[ecMsg.sender_id-1];
								for( ; recv_flag[ecMsg.sender_id-1][scanFrame]; inc_frame_id(scanFrame) )
									clear_recv_flag( ecMsg.sender_id, prev_frame_id(scanFrame) );
							}
						}

						// append the queue to receive queue
						en_recv_queue(recvPtr, recvLen);
					}
					else
					{
						// drop the message if the receive queue is full
#if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
						DEBUG_LOG("ec_remote : but receive_queue is full, discard message");
#endif
					}
				}
				else
				{
#if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
					debugStr = "ec_remote : FIRST_SEND received, from:";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " discarded";
					DEBUG_LOG(debugStr);
#endif
					// some frame before are missing, wait resend
					// discard the frame, but reply, for the sender not to
					// send the frame again
					if( dp_id[ecMsg.sender_id-1] )
					{
						// send ACK
						char replyMsg[sizeof(EcMsgHeader) + CRC_LEN];
						((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id);
						*((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader));
						mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) );
					}
				}
				break;

			case RE_SEND:
				// accept except frameId is wait_to_receive -1 or recv_flag is set
				if( is_waiting_receive( ecMsg.sender_id, ecMsg.frame_id ) )
				{
#if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
					debugStr = "ec_remote : RE_SEND received, from:";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " accepted";
					DEBUG_LOG(debugStr);
#endif
					err_when( ecMsg.sender_id <= 0 || ecMsg.sender_id > MAX_PLAYER);

					if( !is_recv_full() )
					{
						if( dp_id[ecMsg.sender_id-1] )
						{
							// mark recv_flag
							set_recv_flag(ecMsg.sender_id, ecMsg.frame_id);

							// send ACK
							char replyMsg[sizeof(EcMsgHeader) + CRC_LEN];
							((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id);
							*((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader));
							mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) );

							if( ecMsg.frame_id == wait_to_receive[ecMsg.sender_id-1] )
							{
								// clear recv_flag, until it is zero
								char &scanFrame = wait_to_receive[ecMsg.sender_id-1];
								for( ; recv_flag[ecMsg.sender_id-1][scanFrame]; inc_frame_id(scanFrame) )
									clear_recv_flag( ecMsg.sender_id, prev_frame_id(scanFrame) );
							}
						}

						// append the queue to receive queue
						en_recv_queue(recvPtr, recvLen);
					}
					else
					{
						// drop the message if the receive queue is full
#if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
						DEBUG_LOG("ec_remote : but receive_queue is full, discard message");
#endif
					}
				}
				else
				{
#if ( defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
					debugStr = "ec_remote : RE_SEND received, from:";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " discarded";
					DEBUG_LOG(debugStr);
#endif
					// re-dundant frame, discard, but still reply ACK,
					// for the sender not to send the frame again
					if( dp_id[ecMsg.sender_id-1] )
					{
						// send ACK
						char replyMsg[sizeof(EcMsgHeader) + CRC_LEN];
						((EcMsgHeader *)replyMsg)->init(ACKNOW, self_ec_player_id, ecMsg.frame_id);
						*((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader));
						mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, sizeof(replyMsg) );
					}
				}
				break;
			case ACKNOW:
				// mark the frame ack
				if( is_waiting_ack(ecMsg.sender_id, ecMsg.frame_id) )
				{
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 3 )
					debugStr = "ec_remote : ACKNOW received";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " accepted";
					DEBUG_LOG(debugStr);
#endif
					set_ack(ecMsg.sender_id, ecMsg.frame_id);
					clear_acked_frame();
				}
				else
				{
					// discard the frame
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
					debugStr = "ec_remote : ACKNOW received";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " discarded";
					DEBUG_LOG(debugStr);
#endif
				}
				break;
			case NEGACK:
				// re-send only the frameId
				if( is_waiting_ack(ecMsg.sender_id, ecMsg.frame_id) )
				{
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
					debugStr = "ec_remote : NEGACK received";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " accepted";
					DEBUG_LOG(debugStr);
#endif
					char *replyMsg = send_queue[ecMsg.frame_id].queue_buf;
					DWORD replyLen = send_queue[ecMsg.frame_id].length();

					mp_ptr->send( dp_id[ecMsg.sender_id-1], replyMsg, replyLen );
					err_when( replyLen <= sizeof(EcMsgHeader) );

					// don't mark re-send time
					// mark the func_id of the message RE_SEND
					((EcMsgHeader *)replyMsg)->func_id = RE_SEND;

					// recalculate CRC
					*((CRC_TYPE *) (replyMsg + replyLen - CRC_LEN) ) = crc8((unsigned char *)replyMsg, replyLen - CRC_LEN);
					DEBUG_LOG("ec_remote : frame retransmitted");
				}
				else
				{
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2 )
					debugStr = "ec_remote : NEGACK received";
					debugStr += ecMsg.sender_id;
					debugStr += " frame:";
					debugStr += ecMsg.frame_id;
					debugStr += " discarded";
					DEBUG_LOG(debugStr);
#endif
				}
				break;
			default:
				err_here();
			}
		}
		else
		{
			// crc incorrect
			if( recvLen > sizeof(EcMsgHeader) + CRC_LEN )
			{
				char senderId = get_ec_player_id(from);
				if( senderId)
				{
					// send NEGACK frame
					char replyMsg[sizeof(EcMsgHeader) + CRC_LEN];
					((EcMsgHeader *)replyMsg)->init(NEGACK, self_ec_player_id, wait_to_receive[senderId-1]);
					*((CRC_TYPE *)(replyMsg + sizeof(EcMsgHeader))) = crc8((unsigned char *)replyMsg, sizeof(EcMsgHeader));
					mp_ptr->send( dp_id[senderId-1], replyMsg, sizeof(replyMsg) );
				}
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2)
				DEBUG_LOG("ec_remote : long packet corrupted" );
#endif
			}
			else
			{
				// it is probably, ACKNOW/ NEGACK frame, discard it 
#if (defined(DEBUG) && DEBUG_LOG_LEVEL >= 2)
				DEBUG_LOG("ec_remote : short packet corrupted" );
#endif
			}
		}
	}

	// ------ retransmit any un-acked and time-out-ed frame -------//
	clear_acked_frame();
	re_transmit();
}
Beispiel #5
0
void *ack_receiver_thread(void *params) {
    
    struct ack_receiver_thread_parameter *p = (struct ack_receiver_thread_parameter *) params;
    int *sockfd = p->sockfd;
    unsigned long long *chunks_ack_count = p->chunks_ack_count;
    unsigned long long *total_chunks = p->total_chunks;
    unsigned long long *chunk_id_first_unacked = p->chunk_id_first_unacked;
    unsigned char *required_acks = p->required_acks;
    unsigned char **chunks_ack = p->chunks_ack;
    unsigned char **chunk_cache = p->chunk_cache;
    pthread_mutex_t **chunk_cache_mutex = p->chunk_cache_mutex;
    
    size_t header_length = sizeof(struct layer2) + sizeof(struct layer3) + sizeof(struct layer4_udp);
    
    unsigned int i;
    unsigned char buffer[header_length + (*required_acks * FSCP_UDP_ID_BYTES)];
    unsigned long long chunk_id = 0L;

    size_t recvlen;
    
    unsigned long long progress = 101;
    
    struct layer4_udp *buffer_l4 = (struct layer4_udp *) (buffer + sizeof(struct layer2) + sizeof(struct layer3));
    uchar_t *buffer_payload = buffer + header_length;
    
    
    
    // Receive ACK
    while (*chunks_ack_count < *total_chunks) {
        
        recvlen = recv(*sockfd, buffer, header_length + (*required_acks * FSCP_UDP_ID_BYTES), 0);
        if ((recvlen != -1UL) && (recvlen >= header_length + FSCP_UDP_ID_BYTES)) {
            
            // The packet may contain acknowledgement of more than one chunk
            for(i=0; ((i<ntohs(buffer_l4->len)/FSCP_UDP_ID_BYTES) && (i<*required_acks)); i++) {
                
                // Get chunk id
                memcpy(&chunk_id, buffer_payload + i*FSCP_UDP_ID_BYTES, FSCP_UDP_ID_BYTES);
                
                if (likely(chunk_id>0)) {
                    
                    if (unlikely(chunk_id == (1ULL<<(FSCP_UDP_ID_BYTES*8))-1)) {
                        // Receive FIN
                        *chunks_ack_count = *total_chunks;
                        fprintf(stdout, "\b\b\b\b100%%");
                        break;
                    }
                    
                    if (!is_ack(chunks_ack, chunk_id)) {
                        
                        set_ack(chunks_ack, chunk_id, true);
                        *chunks_ack_count = *chunks_ack_count + 1;
                        
                        // Advance to the next unacked id
                        if (chunk_id == *chunk_id_first_unacked) {
                            do {
                                *chunk_id_first_unacked = *chunk_id_first_unacked + 1;
                            } while (is_ack(chunks_ack, *chunk_id_first_unacked));
                        }
                        
                        // Remove cache of the chunk
                        pthread_mutex_lock(*chunk_cache_mutex+(chunk_id-1));
                        free(chunk_cache[chunk_id-1]);
                        pthread_mutex_destroy(*chunk_cache_mutex+(chunk_id-1));
                        
                        #ifdef _DEBUG
                        fprintf(stdout, "[DEBUG] Recv %3llu%%: ACK 0x%.6llx\n", 100*(*chunks_ack_count)/(*total_chunks), chunk_id);
                        #else
                            #ifdef _PROGRESS_ENABLED
                            if (progress != 100*(*chunks_ack_count)/(*total_chunks)) {
                                progress = 100*(*chunks_ack_count)/(*total_chunks);
                                fprintf(stdout, "\b\b\b\b%3llu%%", progress);
                                fflush(stdout);
                            }
                            #endif
                        #endif
                        
                    }
                    
                }
            }
        }
    }
    
    return 0;
}