Skip to content
Extraits de code Groupes Projets
sender.c 7 ko
Newer Older
  • Learn to ignore specific revisions
  • #include "sender_utils.h"
    
    
    
    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]);
        }
    
    
    Samuel de Meester de Ravestein's avatar
    Samuel de Meester de Ravestein a validé
        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");
    
        // 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));
    
        if (pfd == NULL)
    
            close(socket_fd);
    
            close(sending_fd);
    
            ERROR("Calloc failed for pfd");
    
            return EXIT_FAILURE;
        }
    
        // 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);
    
        if (state == NULL)
        {
    
    Samuel de Meester de Ravestein's avatar
    Samuel de Meester de Ravestein a validé
            free(pfd);
    
            close(socket_fd);
            close(sending_fd);
    
            ERROR("Calloc failed for state");
    
        struct timeval closing_pkt_sent_time;
    
        struct timeval curr_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
    
    Samuel de Meester de Ravestein's avatar
    Samuel de Meester de Ravestein a validé
                free(pfd);
    
                state_del(state);
    
                close(socket_fd);
                close(sending_fd);
    
                ERROR("poll function failed");
    
            // 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)
    
    Samuel de Meester de Ravestein's avatar
    Samuel de Meester de Ravestein a validé
                    free(pfd);
    
                    state_del(state);
    
                    close(socket_fd);
                    close(sending_fd);
    
                    ERROR("handle_returning_pkt function failed");
    
            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 !");
    
                        state_del(state);
    
                        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);
    
            }
            else if (pfd->revents & POLLOUT)
            {
    
                if (rvalue == -1)
                {
    
                    // 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 !");
    
                        state_del(state);
    
                        close(socket_fd);
                        close(sending_fd);
                        ERROR("checking_timer function failed");
                        return EXIT_FAILURE;    
                    }
    
        DEBUG("Sender disconnected"); 
    
        
        if (stats_filename != NULL)
        {
            write_stats_to_file(stats_filename, state->stats, SENDER);
        }
    
    
    Samuel de Meester de Ravestein's avatar
    Samuel de Meester de Ravestein a validé
        free(pfd);
    
        state_del(state);
    
        close(sending_fd);
    
        return EXIT_SUCCESS;