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); } } } }
//Splits long message into smaller messages that fit into frames void ll_split_head(LLnode ** head_ptr, int payload_size) { if(head_ptr == NULL || *head_ptr == NULL) return; //Get the message from the head of the linked list LLnode * head = *head_ptr; Cmd* head_cmd = (Cmd*) head->value; char* msg = head_cmd->message; //Do not need to split if(strlen(msg) < payload_size) return; //Actual message splitting part int i; for(i = payload_size; i < strlen(msg); i+= payload_size) { Cmd* next_cmd = (Cmd*) malloc(sizeof(Cmd)); next_cmd->message = (char *) malloc((payload_size+1)*sizeof(char)); memset(next_cmd->message, 0, (payload_size+1)*sizeof(char)); strncpy(next_cmd->message, msg + i, payload_size*sizeof(char)); next_cmd->src_id = head_cmd->src_id; next_cmd->dst_id = head_cmd->dst_id; ll_append_node(head_ptr, next_cmd); } //Cut off the first message with null character head_cmd->message[payload_size] = '\0'; }
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 // struct timeval now; struct timeval tmp; long long interval; if (sender->fin == 2) { return; } if (sender->fin == 1) { } //find the timeout and send out int pos; int seq; gettimeofday(&now, NULL); for (seq = (sender->LAR + 1); seq <= sender->LFS; seq++) { //seq = sender->LAR + 1; pos = seq % sender->SWS; tmp = sender->timestamp[pos]; interval = (now.tv_sec - tmp.tv_sec) * 1000000 + (now.tv_usec - tmp.tv_usec); //if (interval < 100000) if (interval < 50000) return; fprintf(stderr, "sender:timeout!seq=%d\n",seq); fprintf(stderr, "sender,%ld:%ld\n", now.tv_sec, now.tv_usec); fprintf(stderr, "sender,%ld:%ld\n", tmp.tv_sec, tmp.tv_usec); Frame* outgoing_frame; outgoing_frame = (Frame*)sender->buffer[pos]; sender->timestamp[pos] = now; //char * buf = convert_frame_to_char(outgoing_frame); //outgoing_frame->checksum = chksum((unsigned short*) buf, // MAX_FRAME_SIZE / 2); //buf = convert_frame_to_char(outgoing_frame); char* buf = add_chksum(outgoing_frame); char* outgoing_charbuf = buf; print_frame(outgoing_frame); ll_append_node(outgoing_frames_head_ptr, outgoing_charbuf); } }
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_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); } } } }
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_stdinthread(void *threadid) { fd_set read_fds, master_fds; int fd_max; int select_res; int sender_id; int receiver_id; int sscanf_res; size_t input_buffer_size = (size_t) DEFAULT_INPUT_BUFFER_SIZE; char *input_buffer; char *input_message; int input_bytes_read; char input_command[MAX_COMMAND_LENGTH]; Sender *sender; //Zero out fd_sets FD_ZERO(&read_fds); FD_ZERO(&master_fds); //Add standard input to the fd_set FD_SET(STDIN_FILENO, &master_fds); fd_max = STDIN_FILENO; while (1) { //Copy the master set to avoid permanently altering the master set read_fds = master_fds; if ((select_res = select(fd_max + 1, &read_fds, NULL, NULL, NULL)) == -1) { perror("Select failed - exiting program"); pthread_exit(NULL); } //User inputted a string, read in input and prepare to send if (FD_ISSET(STDIN_FILENO, &read_fds)) { input_buffer = (char *) malloc(input_buffer_size * sizeof(char)); //NULL set the entire input buffer memset(input_buffer, 0, input_buffer_size * sizeof(char)); //Read in the command line into the input buffer input_bytes_read = getline(&input_buffer, &input_buffer_size, stdin); //Zero out the readin buffers for the command memset(input_command, 0, MAX_COMMAND_LENGTH * sizeof(char)); //Zero out the memory for the message to communicate input_message = (char *) malloc((input_bytes_read + 1) * sizeof(char)); memset(input_message, 0, (input_bytes_read + 1) * sizeof(char)); //Scan the input for the arguments sscanf_res = sscanf(input_buffer, "%s %d %d %[^\n]", input_command, &sender_id, &receiver_id, input_message); //Number of parsed objects is less than expected if (sscanf_res < 4) { if (strcmp(input_command, "exit") == 0) { free(input_message); free(input_buffer); return 0; } else { fprintf(stderr, "Command is ill-formatted\n"); } } else { if (strcmp(input_command, "msg") == 0) { //Check to ensure that the sender and receiver ids are in the right range if (sender_id >= glb_senders_array_length || sender_id < 0) { fprintf(stderr, "Sender id is invalid\n"); } if (receiver_id >= glb_receivers_array_length || receiver_id < 0) { fprintf(stderr, "Receiver id is invalid\n"); } //Only add if valid if (sender_id < glb_senders_array_length && receiver_id < glb_receivers_array_length && sender_id >= 0 && receiver_id >= 0) { //Add the message to the receive buffer for the appropriate thread Cmd *outgoing_cmd = (Cmd *) malloc(sizeof(Cmd)); char *outgoing_msg = (char *) malloc(sizeof(char) * (strlen(input_message) + 1)); //Copy out the input message into the outgoing command object strcpy(outgoing_msg, input_message); outgoing_cmd->src_id = sender_id; outgoing_cmd->dst_id = receiver_id; outgoing_cmd->message = outgoing_msg; //Add it to the appropriate input buffer sender = &glb_senders_array[sender_id]; //Lock the buffer, add to the input list, and signal the thread pthread_mutex_lock(&sender->buffer_mutex); ll_append_node(&sender->input_cmdlist_head, (void *) outgoing_cmd); pthread_cond_signal(&sender->buffer_cv); pthread_mutex_unlock(&sender->buffer_mutex); } } else { fprintf(stderr, "Unknown command:%s\n", input_buffer); } } //Lastly, free the input_buffer and the input_message free(input_buffer); free(input_message); } } pthread_exit(NULL); }
//********************************************************************* //NOTE: We will overwrite this file, so whatever changes you put here // WILL NOT persist //********************************************************************* void send_frame(char * char_buffer, enum SendFrame_DstType dst_type) { int i = 0, j; char * per_recv_char_buffer; //Multiply out the probabilities to some degree of precision int prob_prec = 1000; int drop_prob = (int) prob_prec * glb_sysconfig.drop_prob; int corrupt_prob = (int) prob_prec * glb_sysconfig.corrupt_prob; int num_corrupt_bits = CORRUPTION_BITS; int corrupt_indices[num_corrupt_bits]; //Pick a random number int random_num = rand() % prob_prec; int random_index; //Drop the packet on the floor if (random_num < drop_prob) { free(char_buffer); return; } //Determine whether to corrupt bits random_num = rand() % prob_prec; if (random_num < corrupt_prob) { //Pick random indices to corrupt for (i=0; i < num_corrupt_bits; i++) { random_index = rand() % MAX_FRAME_SIZE; corrupt_indices[i] = random_index; } } //Determine the array size of the destination objects int array_length = 0; if (dst_type == ReceiverDst) { array_length = glb_receivers_array_length; } else if (dst_type == SenderDst) { array_length = glb_senders_array_length; } //Go through the dst array and add the packet to their receive queues for (i=0; i < array_length; i++) { //Allocate a per receiver char buffer for the message per_recv_char_buffer = (char *) malloc(sizeof(char) * MAX_FRAME_SIZE); memcpy(per_recv_char_buffer, char_buffer, MAX_FRAME_SIZE); //Corrupt the bits (inefficient, should just corrupt one copy and memcpy it if (random_num < corrupt_prob) { //Corrupt bits at the chosen random indices for (j=0; j < num_corrupt_bits; j++) { random_index = corrupt_indices[j]; per_recv_char_buffer[random_index] = ~per_recv_char_buffer[random_index]; } } if (dst_type == ReceiverDst) { Receiver * dst = &glb_receivers_array[i]; pthread_mutex_lock(&dst->buffer_mutex); ll_append_node(&dst->input_framelist_head, (void *) per_recv_char_buffer); pthread_cond_signal(&dst->buffer_cv); pthread_mutex_unlock(&dst->buffer_mutex); } else if (dst_type == SenderDst) { Sender * dst = &glb_senders_array[i]; pthread_mutex_lock(&dst->buffer_mutex); ll_append_node(&dst->input_framelist_head, (void *) per_recv_char_buffer); pthread_cond_signal(&dst->buffer_cv); pthread_mutex_unlock(&dst->buffer_mutex); } } free(char_buffer); return; }
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); } } }
void handle_pending_frame(Sender * sender, LLnode ** outgoing_frames_head_ptr) { Frame* frame; char* buf; if (sender->fin == 2) return; if (sender->fin == 1) return; while ((sender->LFS - sender->LAR) < sender->SWS) { //calc whether LAR has been at the out part //if ((sender->LFS) == (sender->FSS + 1)) if ((sender->LFS) == (sender->FSS)) { //no more packets sender->fin = 1; //print_sender(sender); break; } frame = build_frame(sender); buf = add_chksum(frame); //buf = convert_frame_to_char(frame); // add into the sender buffer; int pos; pos = frame->seq % sender->SWS; free (sender->buffer[pos]); *(sender->buffer + pos) = (struct Frame*)frame; /* buffer lookup Frame* see; int i; for (i = 0; i < sender->SWS; i++) { see = sender->buffer[i]; fprintf(stderr, "%s\n", see->data); } */ struct timeval now; gettimeofday(&now, NULL); //long long t; //long wait_time = 1000000; /* now.tv_usec = now.tv_usec + wait_time; if (now.tv_usec < wait_time) { now.tv_sec++; now.tv_usec = now.tv_usec - wait_time; } */ //now.tv_sec++; sender->timestamp[pos] = now; ll_append_node(outgoing_frames_head_ptr, buf); } }