void handle_timedout_frames(Sender * sender,
                            LLnode ** outgoing_frames_head_ptr)
{
    //TODO: Suggested steps for handling timed out datagrams
    //    1) Iterate through the sliding window protocol information you maintain for each receiver
    //    2) Locate frames that are timed out and add them to the outgoing frames
    //    3) Update the next timeout field on the outgoing frames
    int i = 0;
    struct timeval *time = malloc(sizeof(struct timeval));
    gettimeofday(time, NULL);
    for (;i < SWS; i++) {
        if (sender->sendQ[i].inuse == 1) {
            long timediff = timeval_usecdiff(time, sender->sendQ[i].timeout);
            if (timediff < 0) {
                Frame * outgoing_frame = (Frame *) sender->sendQ[i].msg;
                char * outgoing_msg = convert_frame_to_char(outgoing_frame);
                //fprintf(stderr, "%d frame timing out\n", outgoing_frame->seqNum);
                append_crc(outgoing_msg,MAX_FRAME_SIZE);
                ll_append_node(outgoing_frames_head_ptr, outgoing_msg);
                setTimeOutTime(sender->sendQ[i].timeout);
                //free(outgoing_frame);
            }
        }
    }
        
}
Exemple #2
0
void handle_timedout_frames(Sender * sender,
        LLnode ** outgoing_frames_head_ptr)
{
    //Iterate through the send queue
    int i;
    for(i=0; i < glb_receivers_array_length; i++)
    {
        send_Q ** curr_node = sender->send_q_head[i];
        int lar = sender->LAR[i];
        int lfs = sender->LFS[i];
        while(lar != lfs)
        {
            lar = (lar + 1) % (MAX_SEQ_NUM + 1);
            send_Q * curr = curr_node[lar%WS];
            Frame * sent_frame = curr->frame;
            struct timeval * tv = curr->frame_timeout;
            struct timeval now;
            gettimeofday(&now, NULL);

            //A frame with set timeout is found
            if(tv != NULL)
            {
                //Update timeout field for old, timed out frames
                if(timeval_usecdiff(tv, &now) > 0)
                {
                    fprintf(stderr, "TIMEDOUT DATA %s being resent\n", sent_frame->data);
                    char * outframe_char_buf = convert_frame_to_char(sent_frame);
                    ll_append_node(outgoing_frames_head_ptr, outframe_char_buf);
                    calculate_timeout(curr->frame_timeout);
                }
            }

            //Update timeout field for fresh outgoing frames
            if(tv == NULL && sent_frame != NULL)
            {
                fprintf(stderr, "FRESH DATA %s being sent\n", sent_frame->data);
                curr->frame_timeout = (struct timeval *) malloc(sizeof(struct timeval));
                calculate_timeout(curr->frame_timeout);
            }
        }
    }
}
Exemple #3
0
struct timeval * sender_get_next_expiring_timeval(Sender * sender)
{
    struct timeval* tv = NULL;
    int i,j;

    //Iterate through the send queue for each receiver state
    for(i=0; i < glb_receivers_array_length; i++)
    {
        send_Q ** curr_node = sender->send_q_head[i];
        for(j=0; j < WS; j++)
        {
            send_Q* curr = curr_node[j];

            if(curr->frame_timeout == NULL)
                continue;

            //Found the next expiring timeval
            if(tv == NULL || timeval_usecdiff(tv, curr->frame_timeout) < 0)
                tv = curr->frame_timeout;
        }
    }

    return tv;
}
Exemple #4
0
void * run_sender(void * input_sender)
{    
    struct timespec   time_spec;
    struct timeval    curr_timeval;
    const int WAIT_SEC_TIME = 0;
    const long WAIT_USEC_TIME = 100000;
    Sender * sender = (Sender *) input_sender;    
    LLnode * outgoing_frames_head;
    struct timeval * expiring_timeval;
    long sleep_usec_time, sleep_sec_time;

    //This incomplete sender thread, at a high level, loops as follows:
    //1. Determine the next time the thread should wake up
    //2. Grab the mutex protecting the input_cmd/inframe queues
    //3. Dequeues messages from the input queue and adds them to the outgoing_frames list
    //4. Releases the lock
    //5. Sends out the messages

    while(1)
    {    
        outgoing_frames_head = NULL;

        //Get the current time
        gettimeofday(&curr_timeval, 
                NULL);

        //time_spec is a data structure used to specify when the thread should wake up
        //The time is specified as an ABSOLUTE (meaning, conceptually, you specify 9/23/2010 @ 1pm, wakeup)
        time_spec.tv_sec  = curr_timeval.tv_sec;
        time_spec.tv_nsec = curr_timeval.tv_usec * 1000;

        //Check for the next event we should handle
        expiring_timeval = sender_get_next_expiring_timeval(sender);

        //Perform full on timeout
        if (expiring_timeval == NULL)
        {
            time_spec.tv_sec += WAIT_SEC_TIME;
            time_spec.tv_nsec += WAIT_USEC_TIME * 1000;
        }
        else
        {
            //Take the difference between the next event and the current time
            sleep_usec_time = timeval_usecdiff(&curr_timeval,
                    expiring_timeval);

            //Sleep if the difference is positive
            if (sleep_usec_time > 0)
            {
                sleep_sec_time = sleep_usec_time/1000000;
                sleep_usec_time = sleep_usec_time % 1000000;   
                time_spec.tv_sec += sleep_sec_time;
                time_spec.tv_nsec += sleep_usec_time*1000;
            }   
        }

        //Check to make sure we didn't "overflow" the nanosecond field
        if (time_spec.tv_nsec >= 1000000000)
        {
            time_spec.tv_sec++;
            time_spec.tv_nsec -= 1000000000;
        }


        //*****************************************************************************************
        //NOTE: Anything that involves dequeing from the input frames or input commands should go 
        //      between the mutex lock and unlock, because other threads CAN/WILL access these structures
        //*****************************************************************************************
        pthread_mutex_lock(&sender->buffer_mutex);

        //Check whether anything has arrived
        int input_cmd_length = ll_get_length(sender->input_cmdlist_head);
        int inframe_queue_length = ll_get_length(sender->input_framelist_head);

        //Nothing (cmd nor incoming frame) has arrived, so do a timed wait on the sender's condition variable (releases lock)
        //A signal on the condition variable will wakeup the thread and reaquire the lock
        if (input_cmd_length == 0 &&
                inframe_queue_length == 0)
        {

            pthread_cond_timedwait(&sender->buffer_cv, 
                    &sender->buffer_mutex,
                    &time_spec);
        }
        //Implement this
        handle_incoming_acks(sender,
                &outgoing_frames_head);

        //Implement this
        handle_input_cmds(sender,
                &outgoing_frames_head);

        pthread_mutex_unlock(&sender->buffer_mutex);


        //Implement this
        handle_timedout_frames(sender,
                &outgoing_frames_head);

        //CHANGE THIS AT YOUR OWN RISK!
        //Send out all the frames
        int ll_outgoing_frame_length = ll_get_length(outgoing_frames_head);

        while(ll_outgoing_frame_length > 0)
        {
            LLnode * ll_outframe_node = ll_pop_node(&outgoing_frames_head);
            char * char_buf = (char *)  ll_outframe_node->value;

            //Don't worry about freeing the char_buf, the following function does that
            send_msg_to_receivers(char_buf);

            //Free up the ll_outframe_node
            free(ll_outframe_node);

            ll_outgoing_frame_length = ll_get_length(outgoing_frames_head);
        }
    }
    pthread_exit(NULL);
    return 0;
}