From 972a7a7c2e02c7202a672844ee29db72eb76ecee Mon Sep 17 00:00:00 2001
From: sdemeesterde <samuel.demeester@student.uclouvain.be>
Date: Fri, 15 Apr 2022 13:56:46 +0200
Subject: [PATCH] fix and cleaner sender
---
src/our_utils.c | 9 +++++++--
src/our_utils.h | 11 ++++++++++-
src/sender.c | 39 ++++++++++++++++++++++-----------------
src/sender_utils.c | 26 +++++++++++++-------------
src/sender_utils.h | 18 +++++++++---------
5 files changed, 61 insertions(+), 42 deletions(-)
diff --git a/src/our_utils.c b/src/our_utils.c
index d944f37..545d398 100644
--- a/src/our_utils.c
+++ b/src/our_utils.c
@@ -109,6 +109,11 @@ int wait_for_client(int sfd)
return 0;
}
+unsigned long long int time_milliseconds(struct timeval *time)
+{
+ return ((unsigned long long int) time->tv_sec * 1000) + ((unsigned long long int) time->tv_usec / 1000);
+}
+
void write_stats_to_file(const char * pathname, transfer_stats_t * stats_file, agents_t caller)
{
if (pathname == NULL || stats_file == NULL)
@@ -161,10 +166,10 @@ void write_stats_to_file(const char * pathname, transfer_stats_t * stats_file, a
if (caller == SENDER)
{
- ret = sprintf((char *) &buffer, "min_rtt:%llu ms\n", stats_file->min_rtt);
+ ret = sprintf((char *) &buffer, "min_rtt:%llu\n", stats_file->min_rtt);
ret = write(fd, buffer, strlen(buffer));
- ret = sprintf((char *) &buffer, "max_rtt:%llu ms\n", stats_file->max_rtt);
+ ret = sprintf((char *) &buffer, "max_rtt:%llu\n", stats_file->max_rtt);
ret = write(fd, buffer, strlen(buffer));
ret = sprintf((char *) &buffer, "packet_retransmitted:%llu\n", stats_file->packet_retransmitted);
diff --git a/src/our_utils.h b/src/our_utils.h
index f992c76..9e51517 100644
--- a/src/our_utils.h
+++ b/src/our_utils.h
@@ -14,6 +14,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -41,7 +42,7 @@ typedef struct __attribute__((__packed__))
typedef enum{
SENDER,
RECEIVER,
-}agents_t;
+} agents_t;
/**
@@ -80,6 +81,14 @@ int create_socket(struct sockaddr_in6 *source_addr, int src_port, struct sockadd
*/
int wait_for_client(int sfd);
+/**
+ * @brief Return the in milliseconds
+ *
+ * @param time : Structure representing the in seconds an mico seconds
+ * @return long long int : return the time in milliseconds
+ */
+unsigned long long int time_milliseconds(struct timeval *time);
+
/**
* @brief Writes the content of the stats_file in the pathname file.
*
diff --git a/src/sender.c b/src/sender.c
index b3c6510..d1134d5 100644
--- a/src/sender.c
+++ b/src/sender.c
@@ -111,15 +111,14 @@ int main(int argc, char **argv) {
struct timeval closing_pkt_sent_time;
struct timeval curr_time;
- while ((state->fec_enabled && state->last_pkt_sent != LAST_FEC) || (state->s_window_size != MAX_WINDOW_SIZE) ||
- (!state->fec_enabled && state->last_pkt_sent != CLOSING_PKT))
+ while ((state->last_pkt_sent != CLOSING_PKT) || (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
if (rvalue == -1)
{
free(pfd);
- state_del(state, stats_filename);
+ state_del(state);
close(socket_fd);
close(sending_fd);
ERROR("poll function failed");
@@ -128,20 +127,20 @@ 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 == LAST_FEC && ((curr_time.tv_sec - closing_pkt_sent_time.tv_sec) > SENDER_INACTIVE_TIMEOUT))
+ if (state->last_pkt_sent == CLOSING_PKT && ((time_milliseconds(&curr_time) - time_milliseconds(&closing_pkt_sent_time)) > SENDER_INACTIVE_TIMEOUT))
{
- DEBUG("The sender hasn't received any news from the receiver for too long so it TIMEOUT");
+ DEBUG("The sender hasn't received any news from the receiver for too long so it TIMEOUT.");
break;
}
if ((pfd->revents & POLLIN) && (pfd->revents & POLLOUT))
{
- DEBUG("The sender is reading from the socket");
+ DEBUG("The sender is reading from the socket.");
rvalue = handle_returning_ack_nack(state, socket_fd);
if (rvalue == -1)
{
free(pfd);
- state_del(state, stats_filename);
+ state_del(state);
close(socket_fd);
close(sending_fd);
ERROR("handle_returning_pkt function failed");
@@ -155,26 +154,26 @@ int main(int argc, char **argv) {
rvalue = read_and_send(state, sending_fd, socket_fd);
if (rvalue == -1)
{
- if (state->last_pkt_sent == LAST_FEC)
+ if (state->fec_enabled && state->last_pkt_sent == CLOSING_PKT)
{
- DEBUG("The very last PTYPE_FEC could not be send because the receiver probably disconnected");
+ DEBUG("The very last PTYPE_FEC could not be send because the receiver probably disconnected which is not a problem !");
break;
}
else
{
free(pfd);
- state_del(state, stats_filename);
+ 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 == LAST_FEC)
+ // Let's start the timer after the closing pkt (PTYPE_DATA with length = 0)
+ if (state->last_pkt_sent == CLOSING_PKT)
{
gettimeofday(&closing_pkt_sent_time, NULL);
- DEBUG("A timer of -> %ds <- has started after sending the last FEC pkt !", SENDER_INACTIVE_TIMEOUT);
+ DEBUG("A timer of -> %dms <- has started after sending the last FEC pkt !", SENDER_INACTIVE_TIMEOUT);
}
}
else if (pfd->revents & POLLOUT)
@@ -184,15 +183,15 @@ int main(int argc, char **argv) {
{
// 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 == LAST_FEC)
+ if (state->last_pkt_sent == CLOSING_PKT)
{
- DEBUG("The sender can't send anything to the receiver anymore (which has probably disconnected) so it'll disconnect !");
+ DEBUG("The sender can't send anything to the receiver anymore (which has probably disconnected) so the sender will also disconnect !");
break;
}
else
{
free(pfd);
- state_del(state, stats_filename);
+ state_del(state);
close(socket_fd);
close(sending_fd);
ERROR("checking_timer function failed");
@@ -202,8 +201,14 @@ int main(int argc, char **argv) {
}
}
DEBUG("Sender disconnected");
+
+ if (stats_filename != NULL)
+ {
+ write_stats_to_file(stats_filename, state->stats, SENDER);
+ }
+
free(pfd);
- state_del(state, stats_filename);
+ state_del(state);
close(sending_fd);
close(socket_fd);
return EXIT_SUCCESS;
diff --git a/src/sender_utils.c b/src/sender_utils.c
index 00d055c..f10e3d2 100644
--- a/src/sender_utils.c
+++ b/src/sender_utils.c
@@ -1,11 +1,6 @@
#include "sender_utils.h"
-long long int time_milliseconds(struct timeval *time)
-{
- return ((long long int) time->tv_sec * 1000) + ((long long int) time->tv_usec / 1000);
-}
-
sender_state_t *state_new(bool fec_enabled)
{
sender_state_t *state = (sender_state_t *) calloc(1, sizeof(sender_state_t));
@@ -37,10 +32,8 @@ sender_state_t *state_new(bool fec_enabled)
return state;
}
-void state_del(sender_state_t *state, const char * pathname)
+void state_del(sender_state_t *state)
{
- write_stats_to_file(pathname, state->stats, SENDER);
-
// To be sure, we free the pkt that might not have been freed (in case of an error or timeout)
for (uint8_t i = 0; i < WINDOW_SIZE; i++)
{
@@ -69,7 +62,8 @@ 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->fec_enabled && (state->last_pkt_sent == CLOSING_PKT))
+ // Case: we're in FEC mode, the closing pkt has been sent but we will still send a last FEC if possible
+ else if ((state->fec_enabled) && (state->last_pkt_sent == CLOSING_PKT) && (state->FEC_nbr > 0))
{
return true;
}
@@ -140,6 +134,7 @@ int handle_returning_ack_nack(sender_state_t *state, int socket_fd)
}
else
{
+ state->stats->packet_retransmitted++;
DEBUG("The NACK with the seqnum: %d has been received, so the pkt will be sent back", seqnum);
state->r_window_size = r_window - 1; // -1 Because the receiver doesn't count yet the sended pkt
pkt_t *n_pkt = state->buffer[place];
@@ -168,6 +163,7 @@ int handle_returning_ack_nack(sender_state_t *state, int socket_fd)
}
else
{
+ state->stats->packet_retransmitted++;
DEBUG("The receiver is asking AGAIN, the seqnum: %d so the sender sends it back", seqnum_nack);
state->r_window_size = r_window - 1; // -1 Because the receiver doesn't count yet the sended pkt
pkt_t *n_pkt = state->buffer[place_last_nack];
@@ -188,7 +184,7 @@ int handle_returning_ack_nack(sender_state_t *state, int socket_fd)
{
struct timeval time;
gettimeofday(&time, NULL);
- unsigned long long int delta_time = time_milliseconds(&time) - time_milliseconds(&state->timers[state->tail]);
+ unsigned long long int delta_time = time_milliseconds(&time) - time_milliseconds(&state->timers_first_send[state->tail]);
if (state->stats->min_rtt == 0 || state->stats->min_rtt > delta_time)
{
state->stats->min_rtt = delta_time;
@@ -212,6 +208,7 @@ int handle_returning_ack_nack(sender_state_t *state, int socket_fd)
// Send back the asked ACK if there is one to send back
if (place_last_nack != OUT_OFF_WINDOW)
{
+ state->stats->packet_retransmitted++;
pkt_t *n_pkt = state->buffer[place_last_nack];
if (send_pkt(state, n_pkt, place_last_nack, socket_fd) == -1) return -1;
}
@@ -230,6 +227,7 @@ int checking_timer(sender_state_t *state, int socket_fd)
// When the timer is over, we send the packet back
if ((time_milliseconds(&time) - time_milliseconds(&state->timers[state->tail])) >= TIMER_LIMIT)
{
+ state->stats->packet_retransmitted++;
pkt_t *pkt = state->buffer[state->tail];
DEBUG("The pkt with seqnum: %d has timeout", pkt_get_seqnum(pkt));
if (send_pkt(state, pkt, state->tail, socket_fd) == -1) return -1;
@@ -274,7 +272,6 @@ 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
@@ -306,7 +303,7 @@ int send_FEC(sender_state_t *state, int socket_fd)
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_enabled) && (state->FEC_nbr == 4 || state->last_pkt_sent == CLOSING_PKT))
+ if ((state->fec_enabled) && ((state->FEC_nbr == 4) || ((state->last_pkt_sent == CLOSING_PKT) && (state->FEC_nbr > 0))))
{
return send_FEC(state, socket_fd);
}
@@ -342,7 +339,7 @@ int read_and_send(sender_state_t *state, int sending_fd, int socket_fd)
{
pkt_set_timestamp(pkt, SECOND_TO_LAST_PKT);
state->last_pkt_sent = LAST_DATA_PKT;
- DEBUG("The LAST DATATYPE is being sent !");
+ DEBUG("The LAST PTYPE_DATA is being sent !");
}
else
{
@@ -364,6 +361,9 @@ int read_and_send(sender_state_t *state, int sending_fd, int socket_fd)
{
construct_FEC(state, pkt);
}
+ struct timeval timer;
+ gettimeofday(&timer, NULL);
+ state->timers_first_send[state->head] = timer;
state->map_seqnum_to_buffer_place[pkt_get_seqnum(pkt)] = state->head;
state->head = (state->head + 1) % WINDOW_SIZE;
diff --git a/src/sender_utils.h b/src/sender_utils.h
index 0de1ca2..9d28bd1 100644
--- a/src/sender_utils.h
+++ b/src/sender_utils.h
@@ -19,16 +19,16 @@
#define SEQNUM_RANGE 256
#define TIMER_LIMIT 2000 // It's in milli seconds, in this network, the latency to send is = [0, 2000ms]
-#define SENDER_INACTIVE_TIMEOUT 30 // Only waits 30sec for the ACK of the CLOSING_PKT (the very last sended pkt)
+#define SENDER_INACTIVE_TIMEOUT 30000 // Only waits 30sec (it's in milliseconds) for the ACK of the CLOSING_PKT (the very last sended pkt)
#define WINDOW_SIZE 31
#define OUT_OFF_WINDOW 255
-// It is used to identify what kind of pkt was sent lately
+// It is used to identify what kind of PTYPE_DATA pkt was sent lately
+// /!\ It doesn't trace the sended FEC !
typedef enum {
RANDOM_PKT = 0,
LAST_DATA_PKT = 1,
- CLOSING_PKT = 2,
- LAST_FEC = 3
+ CLOSING_PKT = 2
} last_sended_pkt_t;
@@ -38,13 +38,14 @@ typedef enum {
typedef struct state {
uint8_t r_window_size; // receiver buffer space
uint8_t s_window_size; // sender (our) buffer space
- struct timeval timers[WINDOW_SIZE]; // Time in seconds (corresponds to the timers of the sended pkt)
+ struct timeval timers[WINDOW_SIZE]; // timeval struct corresponding to the last time the pkt was sended
+ struct timeval timers_first_send[WINDOW_SIZE]; // timeval struct corresponding to the first time the pkt was sended (only used for the stats)
pkt_t *buffer[WINDOW_SIZE]; // When the buffer fields are not used, they MUST be se to NULL
uint8_t head; // place last element insert +1 in the buffer (free place) | Head and tail are used to know
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
- last_sended_pkt_t last_pkt_sent; // Can either be: RANDOM_PKT, LAST_DATA_PKT, CLOSING_PKT or LAST_FEC
+ last_sended_pkt_t last_pkt_sent; // Can either be: RANDOM_PKT, LAST_DATA_PKT or CLOSING_PKT
bool fec_enabled;
pkt_t *FEC; // The pkt FEC in construction
uint8_t FEC_nbr; // The number of PTYPE_DATA stacked on FEC
@@ -64,9 +65,8 @@ sender_state_t *state_new(bool fec_enabled);
* @brief Deletion if the structure representing the sender state.
*
* @param state : The variable representing the sender (state).
- * @param pathname
*/
-void state_del(sender_state_t *state, const char * pathname);
+void state_del(sender_state_t *state);
/**
* @brief Checking if the sender is allowed to send a NEW pkt
@@ -81,7 +81,7 @@ void state_del(sender_state_t *state, const char * pathname);
bool can_send(sender_state_t *state);
/**
- * @brief Cautious this function is used for sending and sending back pkt !
+ * @brief Cautious this function is used for sending and sending back PTYPE_DATA pkt !
*
* @param state : The variable representing the sender (state).
* @param pkt : The pkt to be sent.
--
GitLab