⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.java

📁 一个小型网络仿真器的实现
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
              //         to user if multiple ack to our FIN are received!
              //         So do nothing here.
              break;
            case STAT_CLOSING:
              if(tcb.snd_una.getValue()==tcb.snd_nxt.getValue()) {
                //all are acked => FIN is acked
                tcb.status.setValue(STAT_TIME_WAIT);
                tcb.retrans_timer.stop();
                tcb.timewait_timer.start();

                Object [] params=new Object[3];
                params[0]=tcb;
                params[1]=new Integer(TCPUser.CON_CLOSED);
                params[2]=null;
                comp.getSim().enqueue(new SimEvent(MY_NOTIFY_USER,this,this,comp.getSim().now(),params));
                provider.statusChanged();
                return;
              }
              else continue;
          }
          break;

        case STAT_LAST_ACK:
          if(seg.seg_ack==tcb.snd_nxt.getValue()) {
            //the ack for our FIN
            tcb.status.setValue(STAT_CLOSED);
            tcb.retrans_timer.stop();
            tcbs.remove(tcb.key);
            provider.statusChanged();
            return;
          }
          break;

        case STAT_TIME_WAIT:
          if(seg.fin) {
            TCPSegment newseg=new TCPSegment();
            newseg.sourceport=seg.destport;
            newseg.destport=seg.sourceport;
            newseg.seg_seq=tcb.snd_nxt.getValue();
            newseg.seg_ack=tcb.rcv_nxt.getValue();
            newseg.ack=true;
            newseg.seg_wnd=tcb.rcv_wnd.getValue();
            newseg.seg_len=0;
            IPPacket newpacket=new IPPacket();
            newpacket.sourceIP=packet.destIP;
            newpacket.destIP=packet.sourceIP;
            newpacket.protocol=IPPacket.PRO_TCP;
            newpacket.len=46;
            newpacket.payload=newseg;
            send_ip(newpacket);
  
            tcb.timewait_timer.start();
          }
          return;
      }

      //sixth step, check URG bit (ignore for now...)

      //seventh step, process the segment text
      if(tcb.status.getValue()==STAT_ESTABLISHED ||
          tcb.status.getValue()==STAT_FIN_WAIT1 ||
          tcb.status.getValue()==STAT_FIN_WAIT2) {

        if(seg.payload!=null && !seg.payload.isEmpty()) {
          java.util.Iterator i;
          int oldlen=0,len=0;

          if(tcb.output_q.isEmpty()) {
            tcb.userbuf_seq=seg.seg_seq; //set starting seq # in output_q
          }
          else { //already data in output_q, must count as well
            i=tcb.output_q.iterator();
            while(i.hasNext()) {
              oldlen+=((TCPBuffer)i.next()).len;
            }
          }
          i=seg.payload.iterator();
          while(i.hasNext()) {
            TCPBuffer buf=(TCPBuffer)i.next();
            tcb.output_q.add(buf);
            len+=buf.len;
          }
          //SH Added: length agreement check
          if(len!=seg.seg_len && len+1!=seg.seg_len) {
            System.out.println("Warning: TCP payload len and header len mismatch!");
          }
          //SH end

          tcb.rcv_nxt.setValue(seg.seg_seq+len,comp.getSim().now(),provider.getLogFactor());

          len+=oldlen;
          if(tcb.userbuf_len!=0) { //got a receive request pending
            //notify user if enough data or PUSH seen (FIN also implies PUSH)
            if(seg.psh || seg.fin || (tcb.userbuf_len>0 && len>=tcb.userbuf_len)) {
              comp.getSim().enqueue(new SimEvent(MY_RECEIVE_BUF,this,this,comp.getSim().now(),tcb));
            }
          }

          //mark ACK pending
          ack_pending=true;
        }
      }

      //eighth, check FIN bit
      if(seg.fin) {
        tcb.rcv_nxt.setValue(seg.seg_seq+seg.seg_len,comp.getSim().now(),provider.getLogFactor()); //advance RCV.NXT to the end
  
        //mark ACK pending
        ack_pending=true;

        Object [] params=new Object[3];
        params[0]=tcb;
        params[1]=new Integer(TCPUser.CON_CLOSING);
        params[2]=null;
        comp.getSim().enqueue(new SimEvent(MY_NOTIFY_USER,this,this,comp.getSim().now(),params));

        switch(tcb.status.getValue()) {
          case STAT_SYN_RCVD:
          case STAT_ESTABLISHED:
            tcb.status.setValue(STAT_CLOSE_WAIT);
            provider.statusChanged();
            break;
          case STAT_FIN_WAIT1:
            if(tcb.snd_una.getValue()!=tcb.snd_nxt.getValue()) {
              //our FIN not acked yet
              tcb.status.setValue(STAT_CLOSING);
              provider.statusChanged();
              break;
            }
            //our FIN has been acked, flows through. (shouldn't happen though...)
            System.out.println("Warning: Possible double CON_CLOSED issued to TCP user.");
            params=new Object[3];
            params[0]=tcb;
            params[1]=new Integer(TCPUser.CON_CLOSED);
            params[2]=null;
            comp.getSim().enqueue(new SimEvent(MY_NOTIFY_USER,this,this,comp.getSim().now(),params));
            //flows through...
          case STAT_FIN_WAIT2:
            tcb.status.setValue(STAT_TIME_WAIT);
            tcb.retrans_timer.stop();
            tcb.timewait_timer.start();
            provider.statusChanged();
            break;
          case STAT_CLOSE_WAIT:
          case STAT_CLOSING:
          case STAT_LAST_ACK:
            //do nothing
            break;
          case STAT_TIME_WAIT:
            tcb.timewait_timer.start(); //restart the timewait timer
            break;
        }
      }
    } while((seg=getNextSegment(tcb))!=null);

    if(ack_pending) //must send the pending ACK!
      send_new_data(tcb);
  }

  private TCPSegment getNextSegment(TCB tcb) {
    while (!tcb.reseq_q.isEmpty()) {
      TCPSegment seg=(TCPSegment)tcb.reseq_q.get(0);
      if(!isAcceptable(seg,tcb)) {
        tcb.reseq_q.remove(0);
        continue;
      }
      chop_segment_to_window(seg,tcb);
      if(modGT(seg.seg_seq,tcb.rcv_nxt.getValue())) return null;
      tcb.reseq_q.remove(0);
      return seg;
    }
    return null;
  }

  //seqment acceptability test
  private boolean isAcceptable(TCPSegment seg,TCB tcb) {
    if(seg.seg_len==0) {
      if(tcb.rcv_wnd.getValue()==0) {
        if(seg.seg_seq==tcb.rcv_nxt.getValue()) return true;
      }
      else {
        if(modLE(tcb.rcv_nxt.getValue(),seg.seg_seq) &&
            modLT(seg.seg_seq,tcb.rcv_nxt.getValue()+tcb.rcv_wnd.getValue()))
          return true;
      }
    }
    else {
      if(tcb.rcv_wnd.getValue()>0) {
        if(modLE(tcb.rcv_nxt.getValue(),seg.seg_seq) &&
            modLT(seg.seg_seq,tcb.rcv_nxt.getValue()+tcb.rcv_wnd.getValue()))
          return true;
        else if(modLE(tcb.rcv_nxt.getValue(),seg.seg_seq+seg.seg_len-1) &&
            modLT(seg.seg_seq+seg.seg_len-1,tcb.rcv_nxt.getValue()+tcb.rcv_wnd.getValue()))
          return true;
      }
    }
    return false;
  }

  //chopping segment to "ideal", assume it already passed the
  //acceptability test!
  private void chop_segment_to_window(TCPSegment seg,TCB tcb) {
    if(modLT(seg.seg_seq,tcb.rcv_nxt.getValue())) {
      int chopofflen=tcb.rcv_nxt.getValue()-seg.seg_seq;
      seg.seg_seq=tcb.rcv_nxt.getValue();
      seg.seg_len-=chopofflen;
      //cut out the appropriate payload
      if(seg.payload!=null) {
        java.util.Iterator i=seg.payload.iterator();
        while(i.hasNext()) {
          TCPBuffer buf=(TCPBuffer)i.next();
          if(buf.len<=chopofflen) {
            chopofflen-=buf.len;
            i.remove();
          }
          else {
            buf.len-=chopofflen;
            break;
          }
        }
      }
    }
    if(modGT(seg.seg_seq+seg.seg_len,tcb.rcv_nxt.getValue()+tcb.rcv_wnd.getValue())) {
      int chopofflen=(seg.seg_seq+seg.seg_len)-(tcb.rcv_nxt.getValue()+tcb.rcv_wnd.getValue());
      seg.seg_len-=chopofflen;
      //cut out payload from the end
      if(seg.payload!=null) {
        java.util.ListIterator i=seg.payload.listIterator(seg.payload.size());
        while(i.hasPrevious()) {
          TCPBuffer buf=(TCPBuffer)i.previous();
          if(buf.len<=chopofflen) {
            chopofflen-=buf.len;
            i.remove();
          }
          else {
            buf.len-=chopofflen;
            buf.payload=null;
            break;
          }
          if(chopofflen==0) break; //avoid zero chopoff (lost of payload!)
        }
      }
    }
  }

  private void receive_buf(SimEvent e) {
    TCB tcb=(TCB)e.getParams();
    java.util.List payload=new java.util.LinkedList();
    java.util.Iterator i=tcb.output_q.iterator();

    int len=0;
    while(i.hasNext()) {
      TCPBuffer buf=(TCPBuffer)i.next();
      if(len+buf.len<=tcb.userbuf_len || tcb.userbuf_len<0) {
        len+=buf.len;
        i.remove();
        payload.add(buf);
      }
      else {
        buf.len-=tcb.userbuf_len-len;
        if(len<tcb.userbuf_len) {
          TCPBuffer tempbuf=new TCPBuffer();
          tempbuf.len=tcb.userbuf_len-len;
          payload.add(tempbuf);
        }
        len=tcb.userbuf_len;
        break;
      }
    }
    tcb.userbuf_seq+=len;
    tcb.userbuf_len=0;
    tcb.user.notify(TCPUser.RECEIVE_BUF,payload);
  }

  private int init_seq_generator(long cur_tick) {
    return (int)((init_seq + (long)(SimClock.Tick2USec(cur_tick)/4.0)) & 0xffffffffL);
  }

  private long compute_processing_delay() {
    double fuzz=0;
    double delayvar=provider.getDelayVar();

    if(delayvar > 0)
      fuzz=randgen.nextDouble() * (delayvar+delayvar) - delayvar;

    long ticks=SimClock.USec2Tick(provider.getDelay()+fuzz);
    if(ticks<0) ticks=0;

    return ticks;
  }

  private String [] getStatusTags() {
    String [] tags=new String[11];
    tags[0]="CLOSED";
    tags[1]="LISTEN";
    tags[2]="SYN RCVD";
    tags[3]="SYN SENT";
    tags[4]="ESTABLISHED";
    tags[5]="FIN WAIT-1";
    tags[6]="FIN WAIT-2";
    tags[7]="CLOSING";
    tags[8]="TIME WAIT";
    tags[9]="CLOSE WAIT";
    tags[10]="LAST-ACK";
    return tags;
  }


///////////////////////////// Services ///////////////////////////////////

  public java.util.List createParamset() {
    java.util.List parms=new java.util.ArrayList();
    parms.add(new SimParamIntTag("Status",comp,comp.getSim().now(),true,false,getStatusTags(),STAT_CLOSED));
    parms.add(new SimParamInt("SND.UNA",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("SND.NXT",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("SND.WND",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("SND.WL1",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("SND.WL2",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("ISS",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("RCV.NXT",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("RCV.WND",comp,comp.getSim().now(),true,false,provider.getMaxWindowSize()));
    parms.add(new SimParamInt("IRS",comp,comp.getSim().now(),true,false,0));
    parms.add(new SimParamInt("Congestion window",comp,comp.getSim().now(),true,false,provider.getMaxSegmentSize()));
    parms.add(new SimParamInt("Slow start threshold",comp,comp.getSim().now(),true,false,provider.getMaxWindowSize()));
    parms.add(new SimParamDouble("RTT Variation (s)",comp,comp.getSim().now(),true,false,-1));
    parms.add(new SimParamDouble("Smoothed RTT (s)",comp,comp.getSim().now(),true,false,-1));
    parms.add(new SimParamDouble("Retransmission timeout (s)",comp,comp.getSim().now(),true,false,DEFAULT_RETRANS_TIMEOUT));
    return parms;
  }

  //create a new paramset, and set it with the current paramset values,
  //then replace the current paramset with the new one
  public void newParamset(Object k) {
    TCB tcb=(TCB)tcbs.get(k);
    if(tcb==null) return; //no such connection
    TCB temptcb=new TCB();
    java.util.List newparms=createParamset();
    setParamset(temptcb,newparms);
    temptcb.status.setValue(tcb.status.getValue());
    temptcb.snd_una.setValue(tcb.snd_una.getValue());
    temptcb.snd_nxt.setValue(tcb.snd_nxt.getValue());
    temptcb.snd_wnd.setValue(tcb.snd_wnd.getValue());
    temptcb.snd_wl1.setValue(tcb.snd_wl1.getValue());
    temptcb.snd_wl2.setValue(tcb.snd_wl2.getValue());
    temptcb.iss.setValue(tcb.iss.getValue());
    temptcb.rcv_nxt.setValue(tcb.rcv_nxt.getValue());
    temptcb.rcv_wnd.setValue(tcb.rcv_wnd.getValue());
    temptcb.irs.setValue(tcb.irs.getValue());
    temptcb.cwnd.setValue(tcb.cwnd.getValue());
    temptcb.ssthresh.setValue(tcb.ssthresh.getValue());
    temptcb.rttvar.setValue(tcb.rttvar.getValue());
    temptcb.srtt.setValue(tcb.srtt.getValue());
    temptcb.rto.setValue(tcb.rto.getValue());
    setParamset(tcb,newparms);
  }

  private void setParamset(TCB tcb,java.util.List paramset) {
    java.util.Iterator it=paramset.iterator();
    tcb.status=(SimParamIntTag)it.next();
    tcb.snd_una=(SimParamInt)it.next();
    tcb.snd_nxt=(SimParamInt)it.next();
    tcb.snd_wnd=(SimParamInt)it.next();
    tcb.snd_wl1=(SimParamInt)it.next();
    tcb.snd_wl2=(SimParamInt)it.next();
    tcb.iss=(SimParamInt)it.next();
    tcb.rcv_nxt=(SimParamInt)it.next();
    tcb.rcv_wnd=(SimParamInt)it.next();
    tcb.irs=(SimParamInt)it.next();
    tcb.cwnd=(SimParamInt)it.next();
    tcb.ssthresh=(SimParamInt)it.next();
    tcb.rttvar=(SimParamDouble)it.next();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -