Newer
Older
int print_usage(char *prog_name) {
ERROR("Usage:\n\t%s [-f filename] [-s stats_filename] [-c] receiver_ip receiver_port", prog_name);
return EXIT_FAILURE;
}
int main(int argc, char **argv) {
int opt;
char *filename = NULL;
char *stats_filename = NULL;
char *receiver_ip = NULL;
char *receiver_port_err;
bool fec_enabled = false;
uint16_t receiver_port;
while ((opt = getopt(argc, argv, "f:s:hc")) != -1) {
switch (opt) {
case 'f':
filename = optarg;
break;
case 'h':
return print_usage(argv[0]);
case 's':
stats_filename = optarg;
break;
case 'c':
fec_enabled = true;
break;
default:
return print_usage(argv[0]);
}
}
if (optind + 2 != argc) {
ERROR("Unexpected number of positional arguments");
return print_usage(argv[0]);
}
receiver_ip = argv[optind];
receiver_port = (uint16_t) strtol(argv[optind + 1], &receiver_port_err, 10);
if (*receiver_port_err != '\0') {
ERROR("Receiver port parameter is not a number");
return print_usage(argv[0]);
}
DEBUG("Sender has following arguments: \n\t\tfilename is %s,\n\t\tstats_filename is %s,\n\t\tfec_enabled is %d,\n\t\treceiver_ip is %s,\n\t\treceiver_port is %u",
filename, stats_filename, fec_enabled, receiver_ip, receiver_port);
// *** Step 1: Create a socket AND connect ***
struct sockaddr_in6 receiver_addr;
if (real_address(receiver_ip, &receiver_addr) != NULL)
{
ERROR("An error occured when computing the real address from ip");
return EXIT_FAILURE;
}
// create_socket() also creates a connection using connect()
int socket_fd = create_socket(NULL, 0, &receiver_addr, receiver_port);
if (socket_fd == -1)
{
close(socket_fd);
ERROR("An error occured when sender trying to create its connecting socket");
return EXIT_FAILURE;
}
// *** Step 2: Prepare to send ***
int sending_fd;
if (filename == NULL)
sending_fd = 0; // File descriptor for stdin
}
else
{
sending_fd = open(filename, O_RDONLY);
if (sending_fd == -1)
{
close(socket_fd);
ERROR("An error occured while trying to open the file");
return EXIT_FAILURE;
}
// *** Step: Time for sending ***
struct pollfd *pfd = (struct pollfd *) calloc(1, sizeof(struct pollfd));
ERROR("Calloc failed for pfd");
// Socket -> we want to read and write from it
pfd[0].fd = socket_fd;
pfd[0].events = POLLIN | POLLOUT;
sender_state_t *state = state_new(fec_enabled);
close(socket_fd);
close(sending_fd);
ERROR("Calloc failed for state");
return EXIT_FAILURE;
}
struct timeval closing_pkt_sent_time;
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
close(socket_fd);
close(sending_fd);
ERROR("poll function failed");
return EXIT_FAILURE;
}
// Setting a timer only when waiting for the very last ACK
gettimeofday(&curr_time, NULL);
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.");
if ((pfd->revents & POLLIN) && (pfd->revents & POLLOUT))
DEBUG("The sender is reading from the socket.");
rvalue = handle_returning_ack_nack(state, socket_fd);
if (rvalue == -1)
close(socket_fd);
close(sending_fd);
ERROR("handle_returning_pkt function failed");
return EXIT_FAILURE;
}
}
else if (can_send(state) && (pfd->revents & POLLOUT))
DEBUG("The sender will send a pkt on the socket, the current sender window size is: %d | receiver window size: %d",
state->s_window_size, state->r_window_size);
rvalue = read_and_send(state, sending_fd, socket_fd);
if (rvalue == -1)
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 which is not a problem !");
break;
}
else
{
free(pfd);
close(socket_fd);
close(sending_fd);
ERROR("read_and_send function failed");
return EXIT_FAILURE;
}
// 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 -> %dms <- has started after sending the last PTYPE_DATA pkt !", SENDER_INACTIVE_TIMEOUT);
Samuel de Meester de Ravestein
a validé
rvalue = checking_timer(state, socket_fd);
// 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)
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);
close(socket_fd);
close(sending_fd);
ERROR("checking_timer function failed");
return EXIT_FAILURE;
}
if (stats_filename != NULL)
{
write_stats_to_file(stats_filename, state->stats, SENDER);
}