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 send_syn(int socket_desc, int sock_id, int pnum, struct sockaddr_in* to) { //Create a new rudp header with SYN smalloc(struct rudp_hdr,rh); rh->version = htons(RUDP_VERSION); rh->type = htons(RUDP_SYN); int cnum = state[sock_id].curr[pnum]->seqno; int shift = state[sock_id].curr[pnum]->num; rh->seqno = ntohl(cnum - shift); state[sock_id].syn_seqno[pnum] = cnum - shift;; //Send a SYN int nbytes = sizeof(struct rudp_hdr); size_t size = sizeof(struct sockaddr_in); if (sendto(socket_desc,(void*)rh,nbytes,0,(struct sockaddr*)to,size)==-1) return -1; //Change state of (socket,peer) pair to SENT_SYN if (setsstate(sock_id,to,SENT_SYN)==-1) return -1; fprintf(stderr,"Sent SYN with seqno %d\r\n",ntohl(rh->seqno)); //Register timeout for SYN smalloc(struct timeval,current_time); if (gettimeofday(current_time,NULL)<0) { perror("rudp_event_handler: gettimeofday"); return -1; } current_time->tv_usec += RUDP_TIMEOUT*2000; //Create an argument for the event_timeout function state[sock_id].stap[pnum] = (struct timeout_arg*)malloc(sizeof(struct timeout_arg)); state[sock_id].stap[pnum]->seqno = ntohl(rh->seqno); state[sock_id].stap[pnum]->sock_id = sock_id; state[sock_id].stap[pnum]->socket_desc = socket_desc; state[sock_id].syn_timed_out[pnum] = 0; state[sock_id].stap[pnum]->to = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); memcpy(state[sock_id].stap[pnum]->to,to,sizeof(struct sockaddr_in*)); state[sock_id].stap[pnum]->to->sin_addr = to->sin_addr; //Actually register the timeout handlet event_timeout(*current_time,udp_syn_timeoutf,(void*)(state[sock_id].stap[pnum]),"packet timeout"); return 0; }
int send_data(int socket_desc, int sock_id, int pnum, struct sockaddr_in* to) { //Find out how many packets we have to send int packets_to_send = state[sock_id].last_packet[pnum]-state[sock_id].curr[pnum]->num; if (packets_to_send>state[sock_id].window_size[pnum]) packets_to_send = state[sock_id].window_size[pnum]; int i; for (i=0; i<packets_to_send; i++) { //Move to next packet in queue state[sock_id].curr[pnum] = state[sock_id].curr[pnum]->next; //Create a full RUDP packet smalloc(struct entire_rudp_packet, erp); erp->rh.seqno = htonl(state[sock_id].curr[pnum]->seqno); erp->rh.type = htons(RUDP_DATA); erp->rh.version = htons(RUDP_VERSION); erp->rpb.len = state[sock_id].curr[pnum]->rp.len; erp->rpb.data = (char*)malloc(erp->rpb.len); memcpy(erp->rpb.data,state[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_in); if (sendto(socket_desc,(void*)erp,nbytes,0,(struct sockaddr*)to,size)==-1) return -1; fprintf(stderr,"Sent a DATA packet with seqno %d\r\n",ntohl(erp->rh.seqno)); //Decrease window size by 1 state[sock_id].window_size[pnum] -= 1; //Get the time at which the timeout handler for the packet should be called smalloc(struct timeval,current_time); if (gettimeofday(current_time,NULL)<0) { perror("rudp_event_handler: gettimeofday"); return -1; } current_time->tv_usec += RUDP_TIMEOUT*2000; //Create an argument for the event_timeout function state[sock_id].curr[pnum]->tap = (struct timeout_arg*)malloc(sizeof(struct timeout_arg)); state[sock_id].curr[pnum]->tap->seqno = ntohl(erp->rh.seqno); state[sock_id].curr[pnum]->tap->sock_id = sock_id; state[sock_id].curr[pnum]->tap->socket_desc = socket_desc; state[sock_id].curr[pnum]->timed_out = 0; state[sock_id].curr[pnum]->tap->to = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); memcpy(state[sock_id].curr[pnum]->tap->to,to,sizeof(struct sockaddr_in*)); state[sock_id].curr[pnum]->tap->to->sin_addr = to->sin_addr; //Actually register the timeout handlet event_timeout(*current_time,udp_timeoutf,(void*)(state[sock_id].curr[pnum]->tap),"packet timeout"); } //Send a FIN if no data was left if (packets_to_send<1) send_fin(socket_desc,sock_id,pnum,to); 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; }
int rudp_send_dgram(int pkt_type, rudp_session_t rsession) { int i; struct timeval tv; int ret; gettimeofday(&tv, NULL); tv.tv_sec += (time_t)RUDP_TIMEOUT/1000; switch(pkt_type) { case RUDP_DATA: if(RUDP_SESSION_SYN != rsession->state) { printf("rudp_send_dgram(DATA): invalid session state\n"); return -1; } rsession->wend = rsession->wstart; for(i = 0; i < RUDP_WINDOW; ++i) { if(NULL == rsession->wend) { break; } ret = sendto(rsession->rsock->sockfd, (void*)rsession->wend, sizeof(struct _rudp_dgram_t),0, (struct sockaddr*)&(rsession->target), sizeof(struct sockaddr) ); if(ret < 0) { perror("sendto:"); return -1; } rsession->wend->retrans++; rsession->wend = rsession->wend->next; } event_timeout(tv, rudp_ack_time_cb, rsession, "DATA TIMEOUT"); break; case RUDP_SYN: if(RUDP_SESSION_OPENED != rsession->state) { printf("rudp_send_dgram(SYN): invalid session state\n"); return -1; } if(rsession->head == NULL) { rsession->head = (rudp_dgram_t)malloc(sizeof (struct _rudp_dgram_t)); if(rsession->head == NULL) return -1; rsession->head->hdr.version = 1; rsession->head->hdr.type = RUDP_SYN; rsession->head->hdr.seqno = (u_int32_t)rand(); rsession->head->data_len = 0; rsession->head->next = NULL; } ret = sendto(rsession->rsock->sockfd, (void*)rsession->head, sizeof(struct _rudp_dgram_t), 0, (struct sockaddr*)&(rsession->target), sizeof(struct sockaddr) ); if(ret < 0) { perror("sendto:"); return -1; } rsession->head->retrans++; event_timeout(tv, rudp_ack_time_cb, rsession, "SYN TIMEOUT"); break; case RUDP_FIN: if((RUDP_SESSION_DAT == rsession->state) && (rsession->tail != NULL)) { ret = sendto(rsession->rsock->sockfd, (void*)rsession->tail, sizeof(struct _rudp_dgram_t), 0, (struct sockaddr*)&(rsession->target), sizeof(struct sockaddr) ); if(ret < 0) { perror("sendto:"); return -1; } rsession->tail->retrans++; event_timeout(tv, rudp_ack_time_cb, rsession,"FIN TIMEOUT"); } break; } return 0; }
/* Transmit a packet via UDP */ int send_packet(bool_t is_ack, rudp_socket_t rsocket, struct rudp_packet *p, struct sockaddr_in *recipient) { char type[5]; short t=p->header.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("Sending %s packet to %s:%d seq number=%u on socket=%d\n",type, inet_ntoa(recipient->sin_addr), ntohs(recipient->sin_port), p->header.seqno, (int)rsocket); if (DROP != 0 && rand() % DROP == 1) { printf("Dropped\n"); } else { if (sendto((int)rsocket, p, sizeof(struct rudp_packet), 0, (struct sockaddr*)recipient, sizeof(struct sockaddr_in)) < 0) { fprintf(stderr, "rudp_sendto: sendto failed\n"); return -1; } } if(!is_ack) { /* Set a timeout event if the packet isn't an ACK */ struct timeoutargs *timeargs = malloc(sizeof(struct timeoutargs)); if(timeargs == NULL) { fprintf(stderr, "send_packet: Error allocating timeout args\n"); return -1; } timeargs->packet = malloc(sizeof(struct rudp_packet)); if(timeargs->packet == NULL) { fprintf(stderr, "send_packet: Error allocating timeout args packet\n"); return -1; } timeargs->recipient = malloc(sizeof(struct sockaddr_in)); if(timeargs->packet == NULL) { fprintf(stderr, "send_packet: Error allocating timeout args recipient\n"); return -1; } timeargs->fd = rsocket; memcpy(timeargs->packet, p, sizeof(struct rudp_packet)); memcpy(timeargs->recipient, recipient, sizeof(struct sockaddr_in)); struct timeval currentTime; gettimeofday(¤tTime, NULL); struct timeval delay; delay.tv_sec = RUDP_TIMEOUT/1000; delay.tv_usec= 0; struct timeval timeout_time; timeradd(¤tTime, &delay, &timeout_time); struct rudp_socket_list *curr_socket = socket_list_head; while(curr_socket != NULL) { if(curr_socket->rsock == timeargs->fd) { break; } curr_socket = curr_socket->next; } if(curr_socket->rsock == timeargs->fd) { bool_t session_found = false; /* Check if we already have a session for this peer */ struct session *curr_session = curr_socket->sessions_list_head; while(curr_session != NULL) { if(compare_sockaddr(&curr_session->address, timeargs->recipient) == 1) { /* Found an existing session */ session_found = true; break; } curr_session = curr_session->next; } if(session_found) { if(timeargs->packet->header.type == RUDP_SYN) { curr_session->sender->syn_timeout_arg = timeargs; } else if(timeargs->packet->header.type == RUDP_FIN) { curr_session->sender->fin_timeout_arg = timeargs; } else if(timeargs->packet->header.type == RUDP_DATA) { int i; int index; for(i = 0; i < RUDP_WINDOW; i++) { if(curr_session->sender->sliding_window[i] != NULL && curr_session->sender->sliding_window[i]->header.seqno == timeargs->packet->header.seqno) { index = i; } } curr_session->sender->data_timeout_arg[index] = timeargs; } } } event_timeout(timeout_time, timeout_callback, timeargs, "timeout_callback"); } return 0; }