static void recalc_tmo(unsigned long tmo, struct timeval *t0, struct timeval *t) { unsigned long dt; dt = elapsed_msec(t0); dt = (dt < tmo) ? tmo - dt : 0; (void)msec_to_timeval(dt, t); }
/* updates rtt and deviation estimates based on new sample */ void update_rtt(unsigned this_rtt) { // if this is the first packet, make an 'educated guess' as to the rtt and deviation if(sequence_number==0) { rtt = this_rtt; deviation = this_rtt/2; } else { deviation = 0.7*deviation + 0.3*(abs(this_rtt - rtt)); rtt = 0.8*rtt + 0.2*this_rtt; } msec_to_timeval(rtt+4*deviation,&timeout); }
void wait_for_ack(int sock) { // repeatedly send it until we get an ack while(1) { fd_set readset; FD_ZERO(&readset); FD_SET(sock,&readset); struct timeval t; if(window[0].sent_at + timeout > current_msec()) { unsigned msec_until_expiry = window[0].sent_at + timeout - current_msec(); msec_to_timeval(msec_until_expiry,&t); } else { msec_to_timeval(10,&t); } /* // always allow a 1 msec wait if(msec_until_expiry<0) { t.tv_sec = 0; t.tv_usec = 100; // memset(&t,0,sizeof(t)); }*/ int rdy = select(FD_SETSIZE,&readset,0,0,&t); char incoming[1400]; struct hw6_hdr *hdr = (struct hw6_hdr*)incoming; if(rdy>0) { struct sockaddr_in from_addr; unsigned int addrsize = sizeof(from_addr); int recv_count=recvfrom(sock,incoming,1400,0,(struct sockaddr*)&from_addr,&addrsize); if(recv_count<0) { perror("When receiving packet."); return; } } // if we timed out, or got a double acknowledgment, double the timeout value and send again if(rdy==0 || // double acknowledgment only triggers retransmission once per round-trip time (ntohl(hdr->ack_number)==ntohl(window[0].data->sequence_number)-1 && ((current_msec() - window[0].sent_at) > rtt))) { //last_ack_number) { if(rdy==0) fprintf(stderr,"\nTimed out on packet %d, msec %u\n",ntohl(window[0].data->sequence_number),timeval_to_msec(&t));//,msec_until_expiry); else fprintf(stderr,"\nDouble ack indicating loss of packet %d, msec %u\n",ntohl(window[0].data->sequence_number),timeval_to_msec(&t));//,msec_until_expiry); fprintf(stderr,"Window packets: "); for(int p=0;p<packets_outstanding;p++) { fprintf(stderr,"%d, ",ntohl(window[p].data->sequence_number)); } fprintf(stderr,"\n"); timeout *= 2; if(timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT; window_size /=2; if(window_size < 1) window_size=1; ssthresh = window_size; congestion_avoidance = 1; ca_last_increase = current_msec(); for(int i=0;i<packets_outstanding && i<window_size;i++) { fprintf(stderr,"Resending Packet %d with rtt %f dev %f timeout %d ms window %d to %s \n",ntohl(window[i].data->sequence_number),rtt, deviation,timeout,window_size,inet_ntoa(peeraddr.sin_addr)); if(sendto(sock, window[i].data, window[i].len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)) <=0) perror("Couldn't send!"); window[i].retx = 1; window[i].sent_at = current_msec(); // update the timestamp } fprintf(stderr,"Done resending, for now\n"); } else if(rdy==-1) { perror("select error"); } else { /* blow away all the packets acked here */ // fprintf(stderr,"Got ack for %d, time left %d, rtt %d, retx %d\n",ntohl(hdr->ack_number), timeval_to_msec(&t), current_msec() - window[0].sent_at, window[0].retx); int got_ack=0; last_ack_number = ntohl(hdr->ack_number); while(packets_outstanding > 0 && ntohl(hdr->ack_number) >= ntohl(window[0].data->sequence_number)) { if(!window[0].retx) update_rtt(current_msec() - window[0].sent_at); pop_packet(sock); got_ack=1; } if(got_ack) break; if(! (hdr->flags & ACK)) { // ack whatever we have so far struct hw6_hdr ack; ack.flags = ACK; if(ntohl(hdr->sequence_number) == expected_sequence_number) { expected_sequence_number++; } else { fprintf(stderr,"Unexpected non-ACK in rel_send(). Acking what we have so far. \n"); } ack.ack_number = htonl(expected_sequence_number-1); sendto(sock, &ack, sizeof(ack), 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); } } } }
void rel_send(int sock, void *buf, int len) { if(user == UNKNOWN){ user = SENDER; } int flag_ack_checked; int flag_packet_dropped; // make the packet = header + buf char packet[1400]; struct hw7_hdr *hdr = (struct hw7_hdr*)packet; flag_ack_checked = 0; flag_packet_dropped = 0; memset(hdr,0,sizeof(struct hw7_hdr)); hdr->sequence_number = htonl(sequence_number); memcpy(hdr+1,buf,len); fprintf(stderr,"\r<SHUBHAM>Sent Packet - %d with rtt %d dev %d timeout - %d ms \n",sequence_number,rtt, deviation,timeval_to_msec(&timeout)); sendto(sock, packet, sizeof(struct hw7_hdr)+len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); // put packet in queue, flag = ack not rxed, seq_no struct senderQelements *s; s = calloc(sizeof(struct senderQelements),1); s->magic = 'S'; s->ack_rxed = 0; s->retx = 0; s->packet_len = sizeof(struct hw7_hdr) + len; s->sent_time = current_msec(); memcpy(s->packet, packet, s->packet_len); doQInsert((char *)s); // 1. If queue has no. of elements == window size or if this is the close packet if(getCurrentQSize() == window_size || len == 0){ int ack_count; ack_count = 0; // wait for acks from all while(ack_count < window_size) { if(getCurrentQSize() == 0){ //double check...otherwise we might go in infinite loop //remove break; } fd_set readset; FD_ZERO(&readset); FD_SET(sock,&readset); struct timeval t = timeout; // select changes the timeout parameter on some platforms, so make a copy int rdy = select(FD_SETSIZE,&readset,0,0,&t); if(rdy==0) { //send all unacked packets again send_all_unacked_packets_again(sock); flag_packet_dropped = 1; // if we timed out, send again double the timeout value msec_to_timeval(min(1000,2*timeval_to_msec(&timeout)), &timeout); /* fprintf(stderr,"\rSent Packet %d with rtt %d dev %d timeout %d ms ",sequence_number,rtt, deviation,timeval_to_msec(&timeout)); sendto(sock, packet, sizeof(struct hw7_hdr)+len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); //s->retx=1; fprintf(stderr,"\r<SHUBHAM>Retransmitting - Packet %d with rtt %d dev %d timeout %d ms \n",sequence_number,rtt, deviation,timeval_to_msec(&timeout)); */ } else if(rdy==-1) { perror("select error"); } else { char incoming[1400]; struct sockaddr_in from_addr; unsigned int addrsize = sizeof(from_addr); int recv_count=recvfrom(sock,incoming,1400,0,(struct sockaddr*)&from_addr,&addrsize); if(recv_count<0) { perror("When receiving packet."); return; } struct hw7_hdr *hdr = (struct hw7_hdr*)incoming; if(ntohl(hdr->ack_number) >= start_seq_no && ntohl(hdr->ack_number) <= (start_seq_no + window_size - 1)) { fprintf(stderr,"\r<SHUBHAM>Got ack for %d \n",ntohl(hdr->ack_number)); fprintf(stderr,"<SHUBHAM> Ack rxed - %d , start_seq_no , redundant log\n", (ntohl(hdr->ack_number)) - start_seq_no, start_seq_no); struct senderQelements *s; s = getNthElement((ntohl(hdr->ack_number)) - start_seq_no); fprintf(stderr,"<SHUBHAM> nth element in Q packet->seq_no = %d\n", ntohl(((struct hw7_hdr *)s->packet)->sequence_number)); if(s->ack_rxed){ fprintf(stderr,"<SHUBHAM> RE-Ack rxed - %d , doing nothing\n", (ntohl(hdr->ack_number)) - start_seq_no); } else{ ack_count++; if(!s->retx){ // if this is an ack for our present packet, update the rtt and exit update_rtt(current_msec() - s->sent_time); } } s->ack_rxed = 1; //break; } // if it's not an ack, it's the end of the stream. ACK it. // Scenario: 1. Sender sends close, 2. rxer sends ack(it is lost), 3. rxer sends close, 4. sender recives close in rel_send() /*SHUBHAM: todo?? Handle the close part here?? */ if(! (hdr->flags & ACK)) { // ack whatever we have so far struct hw7_hdr ack; ack.flags = ACK; if(ntohl(hdr->sequence_number) == expected_sequence_number) { expected_sequence_number++; } else { fprintf(stderr,"Unexpected non-ACK in rel_send(), size %d. Acking what we have so far. \n",recv_count); } ack.ack_number = htonl(expected_sequence_number-1); fprintf(stderr,"\r<SHUBHAM>Exception: Sending ACK - %d for a non-ack packet receivd \n",ntohl(ack.ack_number)); sendto(sock, &ack, sizeof(ack), 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)); } } flag_ack_checked = 1; } } /* else{ // return, so that user can send next packet. return; } */ if(len == 0 && !flag_ack_checked){ perror("Some problem"); exit(2); } if(flag_ack_checked){ while(getCurrentQSize() > 0){ //make_raghvan_change struct senderQelements *s; s = doQDelete(); free(s); } start_seq_no = start_seq_no + window_size; //make_raghvan_change if(start_seq_no != sequence_number+1){ exit(20); //assert_remove } if(flag_packet_dropped == 1){ decrease_window_size(); } else{ increase_window_size(); } } sequence_number++; }
/* * We end up here due to a osegw_receive, osegw_receive_w_tmo or * osegw_init_async_receive. While we are waiting for a signal, * we must be able to handle "pings" and osegw_cancel_async_receive * from the client. */ int OseGW_PLT_ReceiveRequest_cbk(int skt, int len, char *payload, struct ClientInfo *cinfo) { struct OseGW_ReceiveRequest *req; struct OseGW_TransportHdr thdr; union LINX_SIGNAL *sig; LINX_SIGSELECT *sigsel; int nfds, status, size, linx_skt, sigsel_len; fd_set rfds; struct timeval tv0, tv, *tvp; unsigned int tmo; void *buf; linx_skt = linx_get_descriptor(cinfo->linx); req = (struct OseGW_ReceiveRequest *)payload; sigsel_len = ntohl(req->sigsel_len); buf = NULL; /* 0. This may be a osegw_cancel_async_receive... */ if (sigsel_len == 0) { sig = NULL; size = 0; goto out; } /* 1. Setup signal filter that should be used while polling... */ sigsel = copy_sigselect(req); if (sigsel == NULL) goto e_exit; if (set_sigselect(linx_skt, sigsel) == -1) goto e_exit; /* 2. Setup time-out... */ tmo = ntohl(req->timeout); if (tmo != (unsigned int)~0) { tvp = msec_to_timeval(tmo, &tv); if (gettimeofday(&tv0, NULL) == -1) goto e_exit; } else tvp = NULL; /* Infinite */ again: /* 3. Setup descriptors... */ FD_ZERO(&rfds); FD_SET(linx_skt, &rfds); /* LINX socket */ FD_SET(skt, &rfds); /* TCP socket */ nfds = linx_skt > skt ? linx_skt : skt; /* 4. Wait for a signal, ping or osegw_cancel_async_receive */ status = select(nfds + 1, &rfds, NULL, NULL, tvp); if (status == -1) goto e_exit; if (status == 0) { /* osegw_receive_w_tmo has timed out */ sig = NULL; size = 0; goto out; } if (FD_ISSET(linx_skt, &rfds)) { /* A signal that matches the signal filter is available */ status = linx_receive(cinfo->linx, &sig, sigsel); if (status == -1) goto e_exit; size = linx_sigsize(cinfo->linx, &sig) - sizeof(SIGSELECT); goto out; } if (FD_ISSET(cinfo->sd, &rfds)) { /* Get command */ buf = get_command(skt, &thdr); if (buf == NULL) goto e_exit; switch (thdr.payload_type) { case OseGW_PLT_InterfaceRequest: status = OseGW_PLT_InterfaceRequest_cbk(skt, thdr.payload_len, buf, cinfo); if (status == -1) goto e_exit; /* Compensate for the time spent in select */ if (tvp != NULL) recalc_tmo(tmo, &tv0, &tv); goto again; break; case OseGW_PLT_ReceiveRequest: req = (struct OseGW_ReceiveRequest *)buf; sigsel_len = ntohl(req->sigsel_len); if (sigsel_len != 0) goto e_exit; /* Only cancel async receive is allowed */ sig = NULL; size = 0; goto out; break; default: syslog(LOG_INFO, "Gateway protocol violation detected, " "got type %d while in a receive", thdr.payload_type); goto e_exit; break; } } out: free(buf); free(sigsel); return OseGW_PLT_ReceiveReply_cbk(skt, size, (char *)sig, cinfo); e_exit: free(buf); free(sigsel); return -1; }