void handle_incoming_acks(Sender * sender, LLnode ** outgoing_frames_head_ptr) { //TODO: Suggested steps for handling incoming ACKs // 1) Dequeue the ACK from the sender->input_framelist_head // 2) Convert the char * buffer to a Frame data type // 3) Check whether the frame is corrupted // 4) Check whether the frame is for this sender // 5) Do sliding window protocol for sender/receiver pair int incoming_ack_length = ll_get_length(sender->input_framelist_head); while (incoming_ack_length > 0) { LLnode * ll_ack_node = ll_pop_node(&sender->input_framelist_head); incoming_ack_length = ll_get_length(sender->input_framelist_head); char * raw_char_buf = (char *) ll_ack_node->value; int flag = is_corrupted(raw_char_buf, MAX_FRAME_SIZE); //fprintf(stderr, "SFLAG = %d\n", flag); if (flag == 0) { // fprintf(stderr, "CORRUPTED\n"); break; } Frame * ackFrame = convert_char_to_frame(raw_char_buf); free (raw_char_buf); if (sender->send_id == ackFrame->src_id) { if (!((sender->LAR <= sender->seqNum && ackFrame->seqNum > sender->LAR && ackFrame->seqNum <= sender->seqNum) || (sender->LAR > sender->seqNum && (ackFrame->seqNum > sender->LAR || ackFrame->seqNum <= sender->seqNum)))) break; // fprintf(stderr, "Receiver[%d] Ack #%d\n",ackFrame->dst_id, // ackFrame->seqNum); // fprintf(stderr, "OLD LAR %d and OLD sendQSize %d\n", sender->LAR, sender->sendQSize); do { int i = 0; for (;i < SWS; i++) { if (sender->sendQ[i].inuse == 1) { Frame * qFrame = (Frame *)sender->sendQ[i].msg; if (qFrame->seqNum == sender->LAR){ sender->sendQ[i].inuse = 0; sender->sendQSize--; // fprintf(stderr, "REMOVING FRAME %d\n", qFrame->seqNum); } } } sender->LAR++; } while (sender->LAR != ackFrame->seqNum); //fprintf(stderr, "LAR = %d and SENDQSIZE %d\n", sender->LAR, sender->sendQSize); } free (ackFrame); free (ll_ack_node); } }
void handle_incoming_msgs(Receiver * receiver, LLnode ** outgoing_frames_head_ptr) { //TODO: Suggested steps for handling incoming frames // 1) Dequeue the Frame from the sender->input_framelist_head // 2) Convert the char * buffer to a Frame data type // 3) Check whether the frame is corrupted // 4) Check whether the frame is for this receiver // 5) Do sliding window protocol for sender/receiver pair int incoming_msgs_length = ll_get_length(receiver->input_framelist_head); while (incoming_msgs_length > 0) { //Pop a node off the front of the link list and update the count LLnode * ll_inmsg_node = ll_pop_node(&receiver->input_framelist_head); incoming_msgs_length = ll_get_length(receiver->input_framelist_head); //DUMMY CODE: Print the raw_char_buf //NOTE: You should not blindly print messages! // Ask yourself: Is this message really for me? // Is this message corrupted? // Is this an old, retransmitted message? char * raw_char_buf = (char *) ll_inmsg_node->value; if (chksum_all(raw_char_buf)) { fprintf(stderr, "chksum error\n"); free(raw_char_buf); free(ll_inmsg_node); continue; } Frame * inframe = convert_char_to_frame(raw_char_buf); if (inframe->src == receiver->send_id) { if (inframe->dst == receiver->recv_id) { Frame * outframe; char* buf; outframe = build_ack(receiver, inframe); buf = add_chksum(outframe); print_receiver(receiver); ll_append_node(outgoing_frames_head_ptr, buf); free(outframe); } } //free(inframe); free(raw_char_buf); free(ll_inmsg_node); } }
void handle_incoming_acks(Sender * sender, LLnode ** outgoing_frames_head_ptr) { int incoming_msgs_length = ll_get_length(sender->input_framelist_head); while(incoming_msgs_length > 0) { //Receive the ACK and update the list length LLnode * ll_inmsg_node = ll_pop_node(&sender->input_framelist_head); incoming_msgs_length = ll_get_length(sender->input_framelist_head); //Convert the ACK node to an actual frame char * raw_char_buf = (char *) ll_inmsg_node->value; Frame * inframe = convert_char_to_frame(raw_char_buf); //Don't need the node anymore ll_destroy_node(ll_inmsg_node); //Checks if the frame is corrupted if(crc8(raw_char_buf, MAX_FRAME_SIZE)) { //Checks if this ACK is for this sender if(atoi(inframe->sender_addr) == sender->send_id) { int id = atoi(inframe->receiver_addr); int seqnum = (int) inframe->seqnum; if(is_valid_sender(sender, seqnum, id)) { fprintf(stderr, "ACK %d RECEIVED\n", seqnum); send_Q** buf = sender->send_q_head[id]; int lar = sender->LAR[id]; while(lar != seqnum) { lar = (lar == MAX_SEQ_NUM) ? 0 : lar + 1; free(buf[lar % WS]->frame); free(buf[lar % WS]->frame_timeout); buf[lar % WS]->frame = NULL; buf[lar % WS]->frame_timeout = NULL; } sender->LAR[id] = lar; } } } free(inframe); } }
void handle_incoming_acks(Sender * sender, LLnode ** outgoing_frames_head_ptr) { //TODO: Suggested steps for handling incoming ACKs // 1) Dequeue the ACK from the sender->input_framelist_head // 2) Convert the char * buffer to a Frame data type // 3) Check whether the frame is corrupted // 4) Check whether the frame is for this sender // 5) Do sliding window protocol for sender/receiver pair int incoming_msgs_length = ll_get_length(sender->input_framelist_head); while (incoming_msgs_length > 0) { LLnode * ll_inmsg_node = ll_pop_node(&sender->input_framelist_head); incoming_msgs_length = ll_get_length(sender->input_framelist_head); char * raw_char_buf = (char *) ll_inmsg_node->value; Frame * inframe = convert_char_to_frame(raw_char_buf); short checksum; checksum = chksum((unsigned short*) raw_char_buf, MAX_FRAME_SIZE / 2); if (checksum) { fprintf(stderr, "send checksum error\n"); continue; } free(raw_char_buf); if (sender->send_id == inframe->dst) { if (inframe->flag == ACK) { recv_ack(sender, inframe); } } free(inframe); } }
void handle_incoming_msgs(Receiver *r, LLnode **output_framelist_head) { while( ll_get_length(r->input_framelist_head) > 0 ) { LLnode *msgNode = ll_pop_node(&r->input_framelist_head); char *raw_buf = (char *)msgNode->value; Frame *inframe = convert_char_to_frame(raw_buf); // If corrupted, drop this frame if( !(crc32(inframe, 4+FRAME_PAYLOAD_SIZE) ^ inframe->crc) ) { // if not the right recipient, drop this frame if( r->recv_id == inframe->dst ) { printf("<RECV_%d>:[%s]\n", r->recv_id, inframe->data); char *ack_buf = (char *)malloc(MAX_FRAME_SIZE); memcpy(ack_buf, raw_buf, MAX_FRAME_SIZE); ack_buf[3] = ACK_FLAG; ll_append_node(output_framelist_head, ack_buf); } } free(msgNode); free(raw_buf); free(inframe); } }
void * run_receiver(void * input_receiver) { struct timespec time_spec; struct timeval curr_timeval; const int WAIT_SEC_TIME = 0; const long WAIT_USEC_TIME = 100000; Receiver * receiver = (Receiver *) input_receiver; LLnode * outgoing_frames_head; //This incomplete receiver thread, at a high level, loops as follows: //1. Determine the next time the thread should wake up if there is nothing in the incoming queue(s) //2. Grab the mutex protecting the input_msg queue //3. Dequeues messages from the input_msg queue and prints them //4. Releases the lock //5. Sends out any outgoing messages pthread_cond_init(&receiver->buffer_cv, NULL); pthread_mutex_init(&receiver->buffer_mutex, NULL); while(1) { //NOTE: Add outgoing messages to the outgoing_frames_head pointer outgoing_frames_head = NULL; gettimeofday(&curr_timeval, NULL); //Either timeout or get woken up because you've received a datagram //NOTE: You don't really need to do anything here, but it might be useful for debugging purposes to have the receivers periodically wakeup and print info time_spec.tv_sec = curr_timeval.tv_sec; time_spec.tv_nsec = curr_timeval.tv_usec * 1000; time_spec.tv_sec += WAIT_SEC_TIME; time_spec.tv_nsec += WAIT_USEC_TIME * 1000; if (time_spec.tv_nsec >= 1000000000) { time_spec.tv_sec++; time_spec.tv_nsec -= 1000000000; } //***************************************************************************************** //NOTE: Anything that involves dequeing from the input frames should go // between the mutex lock and unlock, because other threads CAN/WILL access these structures //***************************************************************************************** pthread_mutex_lock(&receiver->buffer_mutex); //Check whether anything arrived int incoming_msgs_length = ll_get_length(receiver->input_framelist_head); if (incoming_msgs_length == 0) { //Nothing has arrived, do a timed wait on the condition variable (which releases the mutex). Again, you don't really need to do the timed wait. //A signal on the condition variable will wake up the thread and reacquire the lock pthread_cond_timedwait(&receiver->buffer_cv, &receiver->buffer_mutex, &time_spec); } handle_incoming_msgs(receiver, &outgoing_frames_head); pthread_mutex_unlock(&receiver->buffer_mutex); //CHANGE THIS AT YOUR OWN RISK! //Send out all the frames user has appended to the outgoing_frames list 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; //The following function frees the memory for the char_buf object send_msg_to_senders(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); }
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; }
void handle_input_cmds(Sender * sender, LLnode ** outgoing_frames_head_ptr) { int input_cmd_length = ll_get_length(sender->input_cmdlist_head); //Split the message if it's too long ll_split_head(&sender->input_cmdlist_head, FRAME_PAYLOAD_SIZE - 1); //Recheck the command queue length to see if stdin_thread dumped a command on us input_cmd_length = ll_get_length(sender->input_cmdlist_head); while (input_cmd_length > 0) { //Pop a node off and update the input_cmd_length LLnode * ll_input_cmd_node = ll_pop_node(&sender->input_cmdlist_head); input_cmd_length = ll_get_length(sender->input_cmdlist_head); //Cast to Cmd type and free up the memory for the node Cmd * outgoing_cmd = (Cmd *) ll_input_cmd_node->value; free(ll_input_cmd_node); //Convert uint16_t to string char* src = malloc(MAC_ADDR_SIZE); char* dst = malloc(MAC_ADDR_SIZE); sprintf(src, "%u", outgoing_cmd->src_id); sprintf(dst, "%u", outgoing_cmd->dst_id); int id = atoi(dst); if(send_q_size(sender, id) < WS) { Frame * outgoing_frame = (Frame *) malloc (sizeof(Frame)); //Populate the outgoing frame's fields strncpy(outgoing_frame->receiver_addr, dst, MAC_ADDR_SIZE); strncpy(outgoing_frame->sender_addr, src, MAC_ADDR_SIZE); strncpy(outgoing_frame->data, outgoing_cmd->message, FRAME_PAYLOAD_SIZE); //Assign seqnum to the outgoing frame outgoing_frame->seqnum = sender->seqnum[id]; char* raw_char_buf = convert_frame_to_char(outgoing_frame); //Assign crc to the outgoing frame outgoing_frame->crc = crc8(raw_char_buf, MAX_FRAME_SIZE); free(raw_char_buf); //At this point, we don't need the outgoing_cmd free(outgoing_cmd->message); free(outgoing_cmd); //Update LFS sender->LFS[id] = sender->seqnum[id]; //Convert the message to the outgoing_charbuf and send it char * outgoing_charbuf = convert_frame_to_char(outgoing_frame); //fprintf(stderr, "MESSAGE %s SENT\n", outgoing_frame->data); ll_append_node(outgoing_frames_head_ptr, outgoing_charbuf); sender->send_q_head[id][sender->seqnum[id] % WS]->frame = malloc(sizeof(Frame)); //Store the sent frame in the sent queue memcpy(sender->send_q_head[id][sender->seqnum[id] % WS]->frame, outgoing_frame, sizeof(Frame)); sender->send_q_head[id][sender->seqnum[id] % WS]->frame_timeout = NULL; free(outgoing_frame); sender->seqnum[id] = (sender->seqnum[id] == 255) ? 0 : sender->seqnum[id] + 1; } else { ll_append_node_at_front(&sender->input_cmdlist_head, outgoing_cmd); input_cmd_length = ll_get_length(sender->input_cmdlist_head); break; } } }
void handle_input_cmds(Sender * sender, LLnode ** outgoing_frames_head_ptr) { //TODO: Suggested steps for handling input cmd // 1) Dequeue the Cmd from sender->input_cmdlist_head // 2) Convert to Frame // 3) Set up the frame according to the sliding window protocol // 4) Compute CRC and add CRC to Frame int input_cmd_length = ll_get_length(sender->input_cmdlist_head); //Recheck the command queue length to see if stdin_thread dumped a command on us input_cmd_length = ll_get_length(sender->input_cmdlist_head); ll_split_head(&sender->input_cmdlist_head, FRAME_PAYLOAD_SIZE - 1); while (input_cmd_length > 0 && sender->sendQSize <= SWS) { // fprintf(stderr, "%d %d\n", input_cmd_length, ll_get_length(sender->input_cmdlist_head)); unsigned char upper = sender->LAR + SWS - 1; //printf("%d %d %d ", sender->LAR, upper, sender->seqNum); if (!((sender->LAR <= upper && sender->seqNum >= sender->LAR && sender->seqNum <= upper) || (sender->LAR > upper && (sender->seqNum >= sender->LAR || sender->seqNum <= upper)))) break; //Pop a node off and update the input_cmd_length LLnode * ll_input_cmd_node = ll_pop_node(&sender->input_cmdlist_head); input_cmd_length = ll_get_length(sender->input_cmdlist_head); //Cast to Cmd type and free up the memory for the node Cmd * outgoing_cmd = (Cmd *) ll_input_cmd_node->value; free(ll_input_cmd_node); //DUMMY CODE: Add the raw char buf to the outgoing_frames list //NOTE: You should not blindly send this message out! // Ask yourself: Is this message actually going to the right receiver (recall that default behavior of send is to broadcast to all receivers)? // Does the receiver have enough space in in it's input queue to handle this message? // Were the previous messages sent to this receiver ACTUALLY delivered to the receiver? int msg_length = strlen(outgoing_cmd->message); if (msg_length > MAX_FRAME_SIZE) { //Do something about messages that exceed the frame size printf("<SEND_%d>: sending messages of length greater than %d is not implemented\n", sender->send_id, MAX_FRAME_SIZE); } else { //This is probably ONLY one step you want Frame * outgoing_frame = (Frame *) malloc (sizeof(Frame)); strcpy(outgoing_frame->data, outgoing_cmd->message); outgoing_frame->src_id = outgoing_cmd->src_id; outgoing_frame->dst_id = outgoing_cmd->dst_id; outgoing_frame->seqNum = sender->seqNum; sender->seqNum++; //if (sender->seqNum >= SWS) // sender->seqNum = 0; //if (sender->seqNum == 5) // sender->seqNum++; //At this point, we don't need the outgoing_cmd free(outgoing_cmd->message); free(outgoing_cmd); //Convert the message to the outgoing_charbuf char * outgoing_charbuf = convert_frame_to_char(outgoing_frame); append_crc(outgoing_charbuf, MAX_FRAME_SIZE); //fprintf(stderr, "Sending %d with data %s\n", outgoing_frame->seqNum,outgoing_frame->data); ll_append_node(outgoing_frames_head_ptr, outgoing_charbuf); int i = 0; for (; i < SWS; i++) { if (sender->sendQ[i].inuse == 0) { sender->sendQSize++; struct timeval * timeout = malloc(sizeof(struct timeval)); setTimeOutTime(timeout); sender->sendQ[i].inuse = 1; sender->sendQ[i].timeout = timeout; sender->sendQ[i].msg =(Frame *)malloc(MAX_FRAME_SIZE); memcpy(sender->sendQ[i].msg,outgoing_frame,MAX_FRAME_SIZE); break; } } free(outgoing_frame); } } }
void handle_input_cmds(Sender * sender, LLnode ** outgoing_frames_head_ptr) { //TODO: Suggested steps for handling input cmd // 1) Dequeue the Cmd from sender->input_cmdlist_head // 2) Convert to Frame // 3) Set up the frame according to the sliding window protocol // 4) Compute CRC and add CRC to Frame int input_cmd_length = ll_get_length(sender->input_cmdlist_head); //Recheck the command queue length to see if stdin_thread dumped a command on us input_cmd_length = ll_get_length(sender->input_cmdlist_head); while (input_cmd_length > 0) { //Pop a node off and update the input_cmd_length LLnode * ll_input_cmd_node = ll_pop_node(&sender->input_cmdlist_head); input_cmd_length = ll_get_length(sender->input_cmdlist_head); //Cast to Cmd type and free up the memory for the node Cmd * outgoing_cmd = (Cmd *) ll_input_cmd_node->value; free(ll_input_cmd_node); //DUMMY CODE: Add the raw char buf to the outgoing_frames list //NOTE: You should not blindly send this message out! // Ask yourself: Is this message actually going to the right receiver (recall that default behavior of send is to broadcast to all receivers)? // Does the receiver have enough space in in it's input queue to handle this message? // Were the previous messages sent to this receiver ACTUALLY delivered to the receiver? int msg_length = strlen(outgoing_cmd->message); if (msg_length > 0) { //init id sender->recv_id = outgoing_cmd->dst_id; //init sender sender->LFS = -1; sender->LAR = -1; sender->SWS = 8; sender->FSS = (msg_length + TEMP_SIZE - 1) / TEMP_SIZE; //sender->FSS = (msg_length + TEMP_SIZE) / TEMP_SIZE; sender->fin = 0;// not fin free(sender->message); sender->message = malloc(msg_length + 1); strcpy(sender->message, outgoing_cmd->message); sender->message_length = msg_length; //init buffer; sender->buffer = (struct Frame**) malloc(8 * sizeof(Frame*)); sender->timestamp = malloc(8 * sizeof(struct timeval)); int i; struct timeval init_time; gettimeofday(&init_time, NULL); init_time.tv_sec += 999999; for (i = 0; i < 8; i++) { sender->buffer[i] = malloc(1); sender->timestamp[i] = init_time; } //print_sender(sender); } else { //This is probably ONLY one step you want Frame * outgoing_frame = (Frame *) malloc (sizeof(Frame)); strcpy(outgoing_frame->data, outgoing_cmd->message); //At this point, we don't need the outgoing_cmd free(outgoing_cmd->message); free(outgoing_cmd); //Convert the message to the outgoing_charbuf char * outgoing_charbuf = convert_frame_to_char(outgoing_frame); //char * outgoing_charbuf = add_chksum(outgoing_frame); ll_append_node(outgoing_frames_head_ptr, outgoing_charbuf); free(outgoing_frame); } } }