diff --git a/src/sender.c b/src/sender.c index 9fe8f3692788c8612d4c4080ad87053d185b2c4e..4b81e0a5a21becac84af61a118334c20ace08322 100644 --- a/src/sender.c +++ b/src/sender.c @@ -118,7 +118,7 @@ int main(int argc, char **argv) { struct timeval closing_pkt_sent_time; struct timeval curr_time; - while (state->last_pkt_sent != CLOSING_PKT || state->s_window_size != MAX_WINDOW_SIZE) + while ((state->last_pkt_sent != CLOSING_PKT && state->last_pkt_sent != LAST_FEC) || state->s_window_size != MAX_WINDOW_SIZE) { // Blocking system call int rvalue = poll(pfd, 1, -1); // -1 means that there are no setted time out @@ -134,7 +134,7 @@ int main(int argc, char **argv) { // Setting a timer only when waiting for the very last ACK gettimeofday(&curr_time, NULL); - if (state->last_pkt_sent == CLOSING_PKT && ((curr_time.tv_sec - closing_pkt_sent_time.tv_sec) > SENDER_INACTIVE_TIMEOUT)) + if (state->last_pkt_sent == LAST_FEC && ((curr_time.tv_sec - closing_pkt_sent_time.tv_sec) > SENDER_INACTIVE_TIMEOUT)) { DEBUG("The sender hasn't received any news from the receiver for too long so it TIMEOUT"); break; @@ -160,18 +160,26 @@ int main(int argc, char **argv) { rvalue = read_and_send(state, sending_fd, socket_fd); if (rvalue == -1) { - free(pfd); - state_del(state); - close(socket_fd); - close(sending_fd); - ERROR("read_and_send function failed"); - return EXIT_FAILURE; + if (state->last_pkt_sent == LAST_FEC) + { + DEBUG("The very last PTYPE_FEC could not be send because the receiver probably disconnected"); + break; + } + else + { + free(pfd); + state_del(state); + close(socket_fd); + close(sending_fd); + ERROR("read_and_send function failed"); + return EXIT_FAILURE; + } } // Let's start the timer for the last pkt sent - if (state->last_pkt_sent == CLOSING_PKT) + if (state->last_pkt_sent == LAST_FEC) { gettimeofday(&closing_pkt_sent_time, NULL); - DEBUG("A timer of -> %ds <- has started after sending the closing pkt for the first time !", SENDER_INACTIVE_TIMEOUT); + DEBUG("A timer of -> %ds <- has started after sending the last FEC pkt !", SENDER_INACTIVE_TIMEOUT); } } else if (pfd->revents & POLLOUT) @@ -179,9 +187,9 @@ int main(int argc, char **argv) { rvalue = checking_timer(state, socket_fd); if (rvalue == -1) { - // If an error occured when trying to send back the CLOSING_PKT, + // If an error occured when trying to send back the CLOSING_PKT (so when the last FEC has been sent), // we guess that the receiver has simply disconnected and the ACK of the CLOSING_PKT was lost. - if (state->last_pkt_sent == CLOSING_PKT) + if (state->last_pkt_sent == LAST_FEC) { DEBUG("The sender can't send anything to the receiver anymore (which has probably disconnected) so it'll disconnect !"); break; diff --git a/src/sender_utils.c b/src/sender_utils.c index b70b96b5c9c20d74874c69f39e99978bc04338e0..bdcdea1edb7aaeaf009d39ab96ca7b4525fa61b1 100644 --- a/src/sender_utils.c +++ b/src/sender_utils.c @@ -21,7 +21,9 @@ sender_state_t *state_new() { state->map_seqnum_to_buffer_place[i] = OUT_OFF_WINDOW; } - state->last_pkt_sent = RANDOM_DATA_PKT; // default + state->last_pkt_sent = RANDOM_PKT; // default + state->FEC = pkt_new(); + state->FEC_nbr = 0; return state; } @@ -35,12 +37,13 @@ void state_del(sender_state_t *state) pkt_del(state->buffer[i]); } } + pkt_del(state->FEC); free(state); } bool can_send(sender_state_t *state) { - if (state->last_pkt_sent == RANDOM_DATA_PKT) + if (state->last_pkt_sent == RANDOM_PKT) { return (state->r_window_size > 0) && (state->s_window_size > 0); } @@ -50,6 +53,11 @@ bool can_send(sender_state_t *state) // it was the end of the file (so that I can set a timer for timeout) return state->s_window_size == MAX_WINDOW_SIZE; } + else if (state->last_pkt_sent == CLOSING_PKT) + { + return true; + } + // Case last FEC has been sended else { return false; @@ -196,69 +204,134 @@ int checking_timer(sender_state_t *state, int socket_fd) return 0; } -int read_and_send(sender_state_t *state, int sending_fd, int socket_fd) +bool is_it_EOF(int sending_fd) { - state->s_window_size--; - state->r_window_size--; - // Checking if we're at the end of the file off_t curr_position = lseek(sending_fd, 0, SEEK_CUR); off_t end_position = lseek(sending_fd, 0, SEEK_END); // put the reader cursor back lseek(sending_fd, curr_position, SEEK_SET); + return (bool) (curr_position == end_position); +} + +void construct_FEC(sender_state_t *state, pkt_t *pkt) +{ + if (state->FEC_nbr == 0) + { + pkt_set_seqnum(state->FEC, pkt_get_seqnum(pkt)); + } - pkt_t *pkt = pkt_new(); - ssize_t nbr_byte_read; + uint16_t length = pkt_get_length(state->FEC) ^ pkt_get_length(pkt); + pkt_set_length(state->FEC, length); - // The file has already been read but we need to send an empty DATA - if (curr_position == end_position) + uint8_t payload[MAX_PAYLOAD_SIZE]; + uint8_t *p1 = (uint8_t *) pkt_get_payload(state->FEC); + uint8_t *p2 = (uint8_t *) pkt_get_payload(pkt); + for (int i = 0; i < MAX_PAYLOAD_SIZE; i++) { - nbr_byte_read = 0; - state->last_pkt_sent = CLOSING_PKT; - DEBUG("The CLOSING pkt has been sent !"); + payload[i] = p1[i] ^ p2[i]; + } + pkt_set_payload(state->FEC, (const char *) payload, MAX_PAYLOAD_SIZE); + + state->FEC_nbr++; +} + +int send_FEC(sender_state_t *state, int socket_fd) +{ + if (state->last_pkt_sent == CLOSING_PKT) + { + state->last_pkt_sent = LAST_FEC; + DEBUG("Sending LAST FEC pkt with seqnum: %d", pkt_get_seqnum(state->FEC)); } else { - nbr_byte_read = read(sending_fd, pkt->payload, MAX_PAYLOAD_SIZE); + DEBUG("Sending FEC pkt with seqnum: %d", pkt_get_seqnum(state->FEC)); } + + char packet_to_be_sent[PKT_MAX_LEN]; + size_t len = PKT_MAX_LEN; + pkt_status_code pkt_status = pkt_encode(state->FEC, packet_to_be_sent, &len); + if (pkt_status != PKT_OK) + { + ERROR("pkt_encode failed with status: %d", pkt_status); + return -1; + } + + ssize_t sent = send(socket_fd, packet_to_be_sent, len, 0); + if (sent == -1) + { + ERROR("The sending (using the function send from <sys/socket.h>) of the pkt failed"); + return -1; + } + memset(state->FEC, 0, sizeof(pkt_t)); + state->FEC_nbr = 0; + return 0; +} - pkt_set_type(pkt, PTYPE_DATA); - pkt_set_tr(pkt, 0); - pkt_set_window(pkt, state->s_window_size); - pkt_set_length(pkt, nbr_byte_read); - pkt_set_seqnum(pkt, state->next_seqnum); - // Sending a specific timestamp to let the receiver knows, it is the second to last pkt - curr_position = lseek(sending_fd, 0, SEEK_CUR); - if (state->last_pkt_sent == RANDOM_DATA_PKT && curr_position == end_position) +int read_and_send(sender_state_t *state, int sending_fd, int socket_fd) +{ + // Checking whether I need to send a PTYPE_FEC or PTYPE_DATA + if (state->FEC_nbr == 4 || state->last_pkt_sent == CLOSING_PKT) { - pkt_set_timestamp(pkt, SECOND_TO_LAST_PKT); - state->last_pkt_sent = LAST_DATA_PKT; - DEBUG("The LAST DATATYPE is being sent !"); + return send_FEC(state, socket_fd); } else { - pkt_set_timestamp(pkt, 0); - } - // put the reader cursor back - lseek(sending_fd, curr_position, SEEK_SET); - - // We set the TR to 0 in order to calculcate the CRC on the header - char modified_header[8]; - memcpy((void *) &modified_header, (void *) &pkt->header, 8); - modified_header[0] = modified_header[0] & TR_SETTER_TO_ZERO; - uint32_t crc1 = htonl(calculate_crc(modified_header, 8)); - pkt_set_crc1(pkt, crc1); + state->s_window_size--; + state->r_window_size--; + + pkt_t *pkt = pkt_new(); + ssize_t nbr_byte_read; + bool is_EOF = is_it_EOF(sending_fd); + + // The file has already been read but we need to send an empty DATA pkt with length = 0 + if (is_EOF) + { + nbr_byte_read = 0; + state->last_pkt_sent = CLOSING_PKT; + DEBUG("The CLOSING pkt is being sent !"); + } + else + { + nbr_byte_read = read(sending_fd, pkt->payload, MAX_PAYLOAD_SIZE); + } - uint32_t crc2 = htonl(calculate_crc((char *) pkt->payload, (uint32_t) pkt_get_length(pkt))); - pkt_set_crc2(pkt, crc2); + pkt_set_type(pkt, PTYPE_DATA); + pkt_set_tr(pkt, 0); + pkt_set_window(pkt, state->s_window_size); + pkt_set_length(pkt, nbr_byte_read); + pkt_set_seqnum(pkt, state->next_seqnum); + // Sending a specific timestamp to let the receiver knows, it is the second to last pkt + is_EOF = is_it_EOF(sending_fd); + if (state->last_pkt_sent == RANDOM_PKT && is_EOF) + { + pkt_set_timestamp(pkt, SECOND_TO_LAST_PKT); + state->last_pkt_sent = LAST_DATA_PKT; + DEBUG("The LAST DATATYPE is being sent !"); + } + else + { + pkt_set_timestamp(pkt, 0); + } + + // We set the TR to 0 in order to calculcate the CRC on the header + char modified_header[8]; + memcpy((void *) &modified_header, (void *) &pkt->header, 8); + modified_header[0] = modified_header[0] & TR_SETTER_TO_ZERO; + uint32_t crc1 = htonl(calculate_crc(modified_header, 8)); + pkt_set_crc1(pkt, crc1); - if (send_pkt(state, pkt, state->head, socket_fd) == -1) return -1; + uint32_t crc2 = htonl(calculate_crc((char *) pkt->payload, (uint32_t) pkt_get_length(pkt))); + pkt_set_crc2(pkt, crc2); - state->map_seqnum_to_buffer_place[pkt_get_seqnum(pkt)] = state->head; - state->head = (state->head + 1) % WINDOW_SIZE; + if (send_pkt(state, pkt, state->head, socket_fd) == -1) return -1; + construct_FEC(state, pkt); - // Careful we need to convert to uint16_t to avoid overflow - state->next_seqnum = (uint8_t) (((uint16_t) state->next_seqnum) + 1) % SEQNUM_RANGE; + state->map_seqnum_to_buffer_place[pkt_get_seqnum(pkt)] = state->head; + state->head = (state->head + 1) % WINDOW_SIZE; - return 0; + // Careful we need to convert to uint16_t to avoid overflow + state->next_seqnum = (uint8_t) (((uint16_t) state->next_seqnum) + 1) % SEQNUM_RANGE; + return 0; + } } \ No newline at end of file diff --git a/src/sender_utils.h b/src/sender_utils.h index c6eb106e9197e1f4d5ed78279f9436a67fce29da..17b11f80b1bfb1f937dc6e276a5cb576849d06cb 100644 --- a/src/sender_utils.h +++ b/src/sender_utils.h @@ -24,9 +24,10 @@ #define OUT_OFF_WINDOW 255 // It is used to identify what kind of pkt was sent lately -#define RANDOM_DATA_PKT 0 +#define RANDOM_PKT 0 #define LAST_DATA_PKT 1 #define CLOSING_PKT 2 +#define LAST_FEC 3 /** @@ -41,7 +42,9 @@ typedef struct state { uint8_t tail; // place oldest element insert in the buffer | the start and end of the sender window (of the sended pkt) uint8_t next_seqnum; uint8_t map_seqnum_to_buffer_place[SEQNUM_RANGE]; // Default value is: OUT_OFF_WINDOW - uint8_t last_pkt_sent; // Can either be: RANDOM_DATA_PKT, LAST_DATA_PKT or CLOSING_PKT + uint8_t last_pkt_sent; // Can either be: RANDOM_PKT, LAST_DATA_PKT, CLOSING_PKT or LAST_FEC + pkt_t *FEC; // The pkt FEC in construction + uint8_t FEC_nbr; // The number of PTYPE_DATA stacked on the FEC } sender_state_t; @@ -101,6 +104,32 @@ int handle_returning_ack_nack(sender_state_t *state, int socket_fd); */ int checking_timer(sender_state_t *state, int socket_fd); +/** + * @brief + * + * @param sending_fd + * @return true + * @return false + */ +bool is_it_EOF(int sending_fd); + +/** + * @brief + * + * @param state + * @param pkt + */ +void construct_FEC(sender_state_t *state, pkt_t *pkt); + +/** + * @brief + * + * @param state + * @param socket_fd + * @return int + */ +int send_FEC(sender_state_t *state, int socket_fd); + /** * @brief When this function is called, the sender MUST be allowed to send a data pkt. * It sends the next pkt and update the variable 'last_pkt_sent' of state.