int acknowledge(int socket_desc, int sock_id, struct sockaddr* to, u_int32_t seqno) { int pnum = getpeernum(sock_id,to); if (seqno==state[sock_id].syn_seqno[pnum]+1) { event_timeout_delete(udp_syn_timeoutf,(void*)state[sock_id].stap[pnum]); state[sock_id].syn_timed_out[pnum] = 0; return 0; } if (seqno==state[sock_id].fin_seqno[pnum]+1) { event_timeout_delete(udp_fin_timeoutf,(void*)state[sock_id].ftap[pnum]); state[sock_id].fin_timed_out[pnum] = 0; return 0; } u_int32_t cnum = state[sock_id].curr[pnum]->tap->seqno; if (seqno<=(cnum+1)) { //Move {shift} packets left int shift = state[sock_id].curr[pnum]->num - state[sock_id].first_packet[pnum]; if (shift>0) { int i; for (i=0;i<shift;i++) { state[sock_id].curr[pnum] = state[sock_id].curr[pnum]->prev; } //Now, move {shift} times right and acknowledge each packet for (i=0;i<shift;i++) { state[sock_id].curr[pnum] = state[sock_id].curr[pnum]->next; event_timeout_delete(udp_timeoutf,state[sock_id].curr[pnum]->tap); if (state[sock_id].window_size[pnum]<3) state[sock_id].window_size[pnum]++; state[sock_id].curr[pnum]->timed_out = 0; if (i<(shift-1)) free(state[sock_id].curr[pnum]->prev); } //Update the number of the first packet state[sock_id].first_packet[pnum]+=shift; } } return 0; }
int udp_fin_timeoutf(int ia, void* va) { struct timeout_arg* targ = (struct timeout_arg*)va; fprintf(stderr,"Timeout for FIN with seqno %d\r\n",targ->seqno); //Deregister timeout function event_timeout_delete(udp_syn_timeoutf,va); int pnum = getpeernum(targ->sock_id,targ->to); //Create a packet for retransmission smalloc(struct entire_rudp_packet, erp); erp->rh.seqno = htonl(targ->seqno); erp->rh.type = htons(RUDP_FIN); erp->rh.version = htons(RUDP_VERSION); erp->rpb.data = NULL; erp->rpb.len = 0; //Actually send packet int nbytes = sizeof(struct rudp_hdr)+erp->rpb.len+16; size_t size = sizeof(struct sockaddr); if (sendto(targ->socket_desc,(void*)erp,nbytes,0,(struct sockaddr*)(targ->to),size)==-1) { perror("udp_fin_timeoutf: sendto"); return -1; } //Register a new timeout for the packet smalloc(struct timeval,current_time); if (gettimeofday(current_time,NULL)<0) { perror("udp_fin_timeoutf: gettimeofday"); return -1; } current_time->tv_usec += RUDP_TIMEOUT*2000; state[targ->sock_id].fin_timed_out[pnum] += 1; if (state[targ->sock_id].fin_timed_out[pnum]>RUDP_MAXRETRANS) { //Call the timeout function if (state[targ->sock_id].udp_event_fh((rudp_socket_t)targ->socket_desc,RUDP_EVENT_TIMEOUT,targ->to)==-1) { perror("udp_fin_timeoutf: event handler failed"); return -1; } return 0; } //Actually register a new timeout function event_timeout(*current_time,udp_fin_timeoutf,(void*)state[targ->sock_id].ftap[pnum],"FIN packet timeout"); }
int rudp_recv_cb(int fd, void *arg) { rudp_socket_t rsock = (rudp_socket_t)arg; rudp_session_t rsession = NULL; rudp_dgram_t rudp_pkt; struct sockaddr_in from; int i; size_t from_len; int ret; char buf[sizeof(struct _rudp_dgram_t)]; memset((char*)&from, 0, sizeof(struct sockaddr_in)); from_len = sizeof(from); ret = recvfrom(fd, buf, sizeof(struct _rudp_dgram_t), 0, (struct sockaddr*)&from, &from_len); if(ret < 0) { perror("recvfrom:"); return -1; } //drop = 1; rudp_pkt = (rudp_dgram_t) buf; #ifdef DROP ++drop; if((drop % 5 == 0) && (rudp_pkt->hdr.type == RUDP_DATA)) { printf("Dropping.. %d\n", drop); return 0; } #endif /* DROP */ if(rudp_pkt->hdr.type == RUDP_ACK) { rsession = rudp_get_session(rsock, &from); if(NULL == rsession) { printf("rudp_recv_cb: No session found\n"); return -1; } } /* Session not correct return immediatedly */ #ifdef DEB printf("Packet type: %d\n\ Packet version: %d\n\ Packet SeqNo.: %d\n", rudp_pkt->hdr.type, rudp_pkt->hdr.version, rudp_pkt->hdr.seqno); #endif /* DEB */ switch(rudp_pkt->hdr.type) { case RUDP_DATA: for(i = 0; i < recv_session; ++i) { /* Check if correct seq no. */ if((SEQ_EQ(recv_seq_no[i], rudp_pkt->hdr.seqno)) && (rsock->recv_handler != NULL)) { rsock->recv_handler(rsock, &from, rudp_pkt->data, rudp_pkt->data_len); rudp_send_ack(rsock, i, &from); break; } } /* Else drop the packet */ break; case RUDP_ACK: //if(rsession->last_seq + 1 != rudp_pkt->hdr.seqno) break; if(rsession->state == RUDP_SESSION_OPENED) { rsession->state = RUDP_SESSION_SYN; event_timeout_delete(rudp_ack_time_cb, rsession); rsession->wstart = rsession->head->next; rudp_send_dgram(RUDP_DATA, rsession); rsession->wsize = 0; } else if(rsession->state == RUDP_SESSION_SYN) { while(SEQ_LT(rsession->wstart->hdr.seqno, rudp_pkt->hdr.seqno)) { rsession->wstart = rsession->wstart->next; if(NULL == rsession->wstart) { event_timeout_delete(rudp_ack_time_cb, rsession); rsession->state = RUDP_SESSION_DAT; rudp_send_dgram(RUDP_FIN, rsession); break; } ++rsession->wsize; } //printf("Window Size: %d\n", rsession->wsize); if((rsession->wsize == RUDP_WINDOW) && (NULL != rsession->wstart)) { event_timeout_delete(rudp_ack_time_cb, rsession); rsession->wsize = 0; rudp_send_dgram(RUDP_DATA, rsession); } } else if(rsession->state == RUDP_SESSION_DAT) { rudp_socket_t r; rsession->state = RUDP_SESSION_FIN; event_timeout_delete(rudp_ack_time_cb, rsession); r = rsession->rsock; rudp_free_session(rsession); #ifdef DEBL printf("nsessions: %d\n", r->nsessions); #endif /* DEBL */ /* Last session on this socket */ if(r->nsessions == 1) { event_fd_delete(rudp_recv_cb, r); r->event_handler(r, RUDP_EVENT_CLOSED, NULL); close(r->sockfd); free(r); } else { /* Decrement the sessions on this socket */ --r->nsessions; } } break; case RUDP_SYN: recv_seq_no[recv_session] = rudp_pkt->hdr.seqno; rudp_send_ack(rsock, recv_session++, &from); all_close = recv_session; break; case RUDP_FIN: for(i = 0; i < recv_session; ++i) { if(SEQ_EQ(recv_seq_no[i], rudp_pkt->hdr.seqno)) { rudp_send_ack(rsock, i, &from); //recv_seq_no[i] = 0; --all_close; break; } } /* Close the socket on the reciever when all the files are recieved */ if(!all_close) rudp_close(rsock); break; } return 0; }
int udp_timeoutf(int ia, void* va) { //Get the packet which was timed out struct timeout_arg* targ = (struct timeout_arg*)va; fprintf(stderr,"Timeout for packet with seqno %d\r\n",targ->seqno); //Deregister timeout function event_timeout_delete(udp_timeoutf,va); //Find which packet we have to retransmit int pnum = getpeernum(targ->sock_id,targ->to); int shift = (state[targ->sock_id].curr[pnum]->seqno)-(targ->seqno); int i; for (i=0;i<shift;i++) { //Move left {shift} times state[targ->sock_id].curr[pnum]=state[targ->sock_id].curr[pnum]->prev; } //Create a packet for retransmission smalloc(struct entire_rudp_packet, erp); erp->rh.seqno = htonl(targ->seqno); erp->rh.type = htons(RUDP_DATA); erp->rh.version = htons(RUDP_VERSION); erp->rpb.len = state[targ->sock_id].curr[pnum]->rp.len; erp->rpb.data = (char*)malloc(erp->rpb.len); memcpy(erp->rpb.data,state[targ->sock_id].curr[pnum]->rp.data,erp->rpb.len); //Actually send packet int nbytes = sizeof(struct rudp_hdr)+erp->rpb.len+16; size_t size = sizeof(struct sockaddr); if (sendto(targ->socket_desc,(void*)erp,nbytes,0,(struct sockaddr*)(targ->to),size)==-1) { //Return to the current packet for (i=0;i<shift;i++) state[targ->sock_id].curr[pnum]=state[targ->sock_id].curr[pnum]->next; perror("udp_timeoutf: sendto"); return -1; } //Register a new timeout for the packet smalloc(struct timeval,current_time); if (gettimeofday(current_time,NULL)<0) { //Return to the current packet for (i=0;i<shift;i++) state[targ->sock_id].curr[pnum]=state[targ->sock_id].curr[pnum]->next; perror("udp_timeoutf: gettimeofday"); return -1; } current_time->tv_usec += RUDP_TIMEOUT*2000; state[targ->sock_id].curr[pnum]->timed_out += 1; if (state[targ->sock_id].curr[pnum]->timed_out>RUDP_MAXRETRANS) { //Return to the current packet for (i=0;i<shift;i++) state[targ->sock_id].curr[pnum]=state[targ->sock_id].curr[pnum]->next; //Call the timeout function if (state[targ->sock_id].udp_event_fh((rudp_socket_t)targ->socket_desc,RUDP_EVENT_TIMEOUT,targ->to)==-1) { perror("udp_timeoutf: event handler failed"); return -1; } return 0; } //Actually register a new timeout function event_timeout(*current_time,udp_timeoutf,(void*)state[targ->sock_id].curr[pnum]->tap,"packet timeout"); //Return to the current packet for (i=0;i<shift;i++) state[targ->sock_id].curr[pnum]=state[targ->sock_id].curr[pnum]->next; return 0; }
/* Callback function executed when something is received on fd */ int receive_callback(int file, void *arg) { char buf[sizeof(struct rudp_packet)]; struct sockaddr_in sender; size_t sender_length = sizeof(struct sockaddr_in); recvfrom(file, &buf, sizeof(struct rudp_packet), 0, (struct sockaddr *)&sender, &sender_length); struct rudp_packet *received_packet = malloc(sizeof(struct rudp_packet)); if(received_packet == NULL) { fprintf(stderr, "receive_callback: Error allocating packet\n"); return -1; } memcpy(received_packet, &buf, sizeof(struct rudp_packet)); struct rudp_hdr rudpheader = received_packet->header; char type[5]; short t = rudpheader.type; if(t == 1) strcpy(type, "DATA"); else if(t == 2) strcpy(type, "ACK"); else if(t == 4) strcpy(type, "SYN"); else if(t==5) strcpy(type, "FIN"); else strcpy(type, "BAD"); printf("Received %s packet from %s:%d seq number=%u on socket=%d\n",type, inet_ntoa(sender.sin_addr), ntohs(sender.sin_port),rudpheader.seqno,file); /* Locate the correct socket in the socket list */ if(socket_list_head == NULL) { fprintf(stderr, "Error: attempt to receive on invalid socket. No sockets in the list\n"); return -1; } else { /* We have sockets to check */ struct rudp_socket_list *curr_socket = socket_list_head; while(curr_socket != NULL) { if((int)curr_socket->rsock == file) { break; } curr_socket = curr_socket->next; } if((int)curr_socket->rsock == file) { /* We found the correct socket, now see if a session already exists for this peer */ if(curr_socket->sessions_list_head == NULL) { /* The list is empty, so we check if the sender has initiated the protocol properly (by sending a SYN) */ if(rudpheader.type == RUDP_SYN) { /* SYN Received. Create a new session at the head of the list */ u_int32_t seqno = rudpheader.seqno + 1; create_receiver_session(curr_socket, seqno, &sender); /* Respond with an ACK */ struct rudp_packet *p = create_rudp_packet(RUDP_ACK, seqno, 0, NULL); send_packet(true, (rudp_socket_t)file, p, &sender); free(p); } else { /* No sessions exist and we got a non-SYN, so ignore it */ } } else { /* Some sessions exist to be checked */ bool_t session_found = false; struct session *curr_session = curr_socket->sessions_list_head; struct session *last_session; while(curr_session != NULL) { if(curr_session->next == NULL) { last_session = curr_session; } if(compare_sockaddr(&curr_session->address, &sender) == 1) { /* Found an existing session */ session_found = true; break; } curr_session = curr_session->next; } if(session_found == false) { /* No session was found for this peer */ if(rudpheader.type == RUDP_SYN) { /* SYN Received. Send an ACK and create a new session */ u_int32_t seqno = rudpheader.seqno + 1; create_receiver_session(curr_socket, seqno, &sender); struct rudp_packet *p = create_rudp_packet(RUDP_ACK, seqno, 0, NULL); send_packet(true, (rudp_socket_t)file, p, &sender); free(p); } else { /* Session does not exist and non-SYN received - ignore it */ } } else { /* We found a matching session */ if(rudpheader.type == RUDP_SYN) { if(curr_session->receiver == NULL || curr_session->receiver->status == OPENING) { /* Create a new receiver session and ACK the SYN*/ struct receiver_session *new_receiver_session = malloc(sizeof(struct receiver_session)); if(new_receiver_session == NULL) { fprintf(stderr, "receive_callback: Error allocating receiver session\n"); return -1; } new_receiver_session->expected_seqno = rudpheader.seqno + 1; new_receiver_session->status = OPENING; new_receiver_session->session_finished = false; curr_session->receiver = new_receiver_session; u_int32_t seqno = curr_session->receiver->expected_seqno; struct rudp_packet *p = create_rudp_packet(RUDP_ACK, seqno, 0, NULL); send_packet(true, (rudp_socket_t)file, p, &sender); free(p); } else { /* Received a SYN when there is already an active receiver session, so we ignore it */ } } if(rudpheader.type == RUDP_ACK) { u_int32_t ack_sqn = received_packet->header.seqno; if(curr_session->sender->status == SYN_SENT) { /* This an ACK for a SYN */ u_int32_t syn_sqn = curr_session->sender->seqno; if( (ack_sqn - 1) == syn_sqn) { /* Delete the retransmission timeout */ event_timeout_delete(timeout_callback, curr_session->sender->syn_timeout_arg); struct timeoutargs *t = (struct timeoutargs *)curr_session->sender->syn_timeout_arg; free(t->packet); free(t->recipient); free(t); curr_session->sender->status = OPEN; while(curr_session->sender->data_queue != NULL) { /* Check if the window is already full */ if(curr_session->sender->sliding_window[RUDP_WINDOW-1] != NULL) { break; } else { int index; int i; /* Find the first unused window slot */ for(i = RUDP_WINDOW-1; i >= 0; i--) { if(curr_session->sender->sliding_window[i] == NULL) { index = i; } } /* Send packet, add to window and remove from queue */ u_int32_t seqno = ++syn_sqn; int len = curr_session->sender->data_queue->len; char *payload = curr_session->sender->data_queue->item; struct rudp_packet *datap = create_rudp_packet(RUDP_DATA, seqno, len, payload); curr_session->sender->seqno += 1; curr_session->sender->sliding_window[index] = datap; curr_session->sender->retransmission_attempts[index] = 0; struct data *temp = curr_session->sender->data_queue; curr_session->sender->data_queue = curr_session->sender->data_queue->next; free(temp->item); free(temp); send_packet(false, (rudp_socket_t)file, datap, &sender); } } } } else if(curr_session->sender->status == OPEN) { /* This is an ACK for DATA */ if(curr_session->sender->sliding_window[0] != NULL) { if(curr_session->sender->sliding_window[0]->header.seqno == (rudpheader.seqno-1)) { /* Correct ACK received. Remove the first window item and shift the rest left */ event_timeout_delete(timeout_callback, curr_session->sender->data_timeout_arg[0]); struct timeoutargs *args = (struct timeoutargs *)curr_session->sender->data_timeout_arg[0]; free(args->packet); free(args->recipient); free(args); free(curr_session->sender->sliding_window[0]); int i; if(RUDP_WINDOW == 1) { curr_session->sender->sliding_window[0] = NULL; curr_session->sender->retransmission_attempts[0] = 0; curr_session->sender->data_timeout_arg[0] = NULL; } else { for(i = 0; i < RUDP_WINDOW - 1; i++) { curr_session->sender->sliding_window[i] = curr_session->sender->sliding_window[i+1]; curr_session->sender->retransmission_attempts[i] = curr_session->sender->retransmission_attempts[i+1]; curr_session->sender->data_timeout_arg[i] = curr_session->sender->data_timeout_arg[i+1]; if(i == RUDP_WINDOW-2) { curr_session->sender->sliding_window[i+1] = NULL; curr_session->sender->retransmission_attempts[i+1] = 0; curr_session->sender->data_timeout_arg[i+1] = NULL; } } } while(curr_session->sender->data_queue != NULL) { if(curr_session->sender->sliding_window[RUDP_WINDOW-1] != NULL) { break; } else { int index; int i; /* Find the first unused window slot */ for(i = RUDP_WINDOW-1; i >= 0; i--) { if(curr_session->sender->sliding_window[i] == NULL) { index = i; } } /* Send packet, add to window and remove from queue */ curr_session->sender->seqno = curr_session->sender->seqno + 1; u_int32_t seqno = curr_session->sender->seqno; int len = curr_session->sender->data_queue->len; char *payload = curr_session->sender->data_queue->item; struct rudp_packet *datap = create_rudp_packet(RUDP_DATA, seqno, len, payload); curr_session->sender->sliding_window[index] = datap; curr_session->sender->retransmission_attempts[index] = 0; struct data *temp = curr_session->sender->data_queue; curr_session->sender->data_queue = curr_session->sender->data_queue->next; free(temp->item); free(temp); send_packet(false, (rudp_socket_t)file, datap, &sender); } } if(curr_socket->close_requested) { /* Can the socket be closed? */ struct session *head_sessions = curr_socket->sessions_list_head; while(head_sessions != NULL) { if(head_sessions->sender->session_finished == false) { if(head_sessions->sender->data_queue == NULL && head_sessions->sender->sliding_window[0] == NULL && head_sessions->sender->status == OPEN) { head_sessions->sender->seqno += 1; struct rudp_packet *p = create_rudp_packet(RUDP_FIN, head_sessions->sender->seqno, 0, NULL); send_packet(false, (rudp_socket_t)file, p, &head_sessions->address); free(p); head_sessions->sender->status = FIN_SENT; } } head_sessions = head_sessions->next; } } } } } else if(curr_session->sender->status == FIN_SENT) { /* Handle ACK for FIN */ if( (curr_session->sender->seqno + 1) == received_packet->header.seqno) { event_timeout_delete(timeout_callback, curr_session->sender->fin_timeout_arg); struct timeoutargs *t = curr_session->sender->fin_timeout_arg; free(t->packet); free(t->recipient); free(t); curr_session->sender->session_finished = true; if(curr_socket->close_requested) { /* See if we can close the socket */ struct session *head_sessions = curr_socket->sessions_list_head; bool_t all_done = true; while(head_sessions != NULL) { if(head_sessions->sender->session_finished == false) { all_done = false; } else if(head_sessions->receiver != NULL && head_sessions->receiver->session_finished == false) { all_done = false; } else { free(head_sessions->sender); if(head_sessions->receiver) { free(head_sessions->receiver); } } struct session *temp = head_sessions; head_sessions = head_sessions->next; free(temp); } if(all_done) { if(curr_socket->handler != NULL) { curr_socket->handler((rudp_socket_t)file, RUDP_EVENT_CLOSED, &sender); event_fd_delete(receive_callback, (rudp_socket_t)file); close(file); free(curr_socket); } } } } else { /* Received incorrect ACK for FIN - ignore it */ } } } else if(rudpheader.type == RUDP_DATA) { /* Handle DATA packet. If the receiver is OPENING, it can transition to OPEN */ if(curr_session->receiver->status == OPENING) { if(rudpheader.seqno == curr_session->receiver->expected_seqno) { curr_session->receiver->status = OPEN; } } if(rudpheader.seqno == curr_session->receiver->expected_seqno) { /* Sequence numbers match - ACK the data */ u_int32_t seqno = rudpheader.seqno + 1; curr_session->receiver->expected_seqno = seqno; struct rudp_packet *p = create_rudp_packet(RUDP_ACK, seqno, 0, NULL); send_packet(true, (rudp_socket_t)file, p, &sender); free(p); /* Pass the data up to the application */ if(curr_socket->recv_handler != NULL) curr_socket->recv_handler((rudp_socket_t)file, &sender, (void*)&received_packet->payload, received_packet->payload_length); } /* Handle the case where an ACK was lost */ else if(SEQ_GEQ(rudpheader.seqno, (curr_session->receiver->expected_seqno - RUDP_WINDOW)) && SEQ_LT(rudpheader.seqno, curr_session->receiver->expected_seqno)) { u_int32_t seqno = rudpheader.seqno + 1; struct rudp_packet *p = create_rudp_packet(RUDP_ACK, seqno, 0, NULL); send_packet(true, (rudp_socket_t)file, p, &sender); free(p); } } else if(rudpheader.type == RUDP_FIN) { if(curr_session->receiver->status == OPEN) { if(rudpheader.seqno == curr_session->receiver->expected_seqno) { /* If the FIN is correct, we can ACK it */ u_int32_t seqno = curr_session->receiver->expected_seqno + 1; struct rudp_packet *p = create_rudp_packet(RUDP_ACK, seqno, 0, NULL); send_packet(true, (rudp_socket_t)file, p, &sender); free(p); curr_session->receiver->session_finished = true; if(curr_socket->close_requested) { /* Can we close the socket now? */ struct session *head_sessions = curr_socket->sessions_list_head; int all_done = true; while(head_sessions != NULL) { if(head_sessions->sender->session_finished == false) { all_done = false; } else if(head_sessions->receiver != NULL && head_sessions->receiver->session_finished == false) { all_done = false; } else { free(head_sessions->sender); if(head_sessions->receiver) { free(head_sessions->receiver); } } struct session *temp = head_sessions; head_sessions = head_sessions->next; free(temp); } if(all_done) { if(curr_socket->handler != NULL) { curr_socket->handler((rudp_socket_t)file, RUDP_EVENT_CLOSED, &sender); event_fd_delete(receive_callback, (rudp_socket_t)file); close(file); free(curr_socket); } } } } else { /* FIN received with incorrect sequence number - ignore it */ } } } } } } } free(received_packet); return 0; }