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

📄 tcp.java

📁 一个小型网络仿真器的实现
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
    if(tcb.input_q.isEmpty() && tcb.userclosing) { //see if closing
      send_fin(tcb);
    }
  }

  private void output_pkt(TCB tcb,int offset,int len,java.util.List payload,
                            boolean push) {
    TCPSegment seg=new TCPSegment();
    seg.sourceport=tcb.key.source_port;
    seg.destport=tcb.key.dest_port;
    seg.seg_seq=offset;
    seg.ack=true;
    seg.seg_ack=tcb.rcv_nxt.getValue();
    seg.seg_wnd=tcb.rcv_wnd.getValue();
    seg.seg_len=len;
    seg.psh=push;
    seg.payload=payload;

    IPPacket packet=new IPPacket();
    packet.sourceIP=tcb.key.source_ip;
    packet.destIP=tcb.key.dest_ip;
    packet.protocol=IPPacket.PRO_TCP;
    packet.len=Math.max(46,40+len); //note: ip & tcp headers each 20 bytes
    packet.payload=seg;

    send_ip(packet);
  }

  private void send_fin(TCB tcb) {
    TCPSegment seg=new TCPSegment();
    seg.sourceport=tcb.key.source_port;
    seg.destport=tcb.key.dest_port;
    seg.seg_seq=tcb.snd_nxt.getValue();
    seg.seg_ack=tcb.rcv_nxt.getValue();
    seg.ack=true;
    seg.fin=true;
    seg.seg_len=1;
    seg.seg_wnd=tcb.rcv_wnd.getValue();
    IPPacket packet=new IPPacket();
    packet.sourceIP=tcb.key.source_ip;
    packet.destIP=tcb.key.dest_ip;
    packet.protocol=IPPacket.PRO_TCP;
    packet.len=46;
    packet.payload=seg;
    send_ip(packet);

    tcb.snd_nxt.setValue(tcb.snd_nxt.getValue() + 1,comp.getSim().now(),provider.getLogFactor());

    //retrans q & timer
    TCPBuffer buf=new TCPBuffer();
    buf.fin=true;
    buf.len=1;
    tcb.retrans_q.add(buf);
    if(!tcb.retrans_timer.isRunning()) tcb.retrans_timer.start();

    tcb.userclosing=false;

    if(tcb.status.getValue()==STAT_CLOSE_WAIT) {
      tcb.status.setValue(STAT_LAST_ACK);
        //Original RFC's state changed to STAT_CLOSING, but the diagram
        //  shows that it should be LAST_ACK after CLOSE_WAIT
      provider.statusChanged();
    }
  }

  private void updateRTT(TCB tcb) {
    double K=4;
    double R=SimClock.Tick2Sec(comp.getSim().now()-tcb.rtt_tick);
    if(tcb.srtt.getValue()<0) { //first time
      tcb.srtt.setValue(R,comp.getSim().now(),provider.getLogFactor());
      tcb.rttvar.setValue(R/2,comp.getSim().now(),provider.getLogFactor());
    }
    else {
      tcb.rttvar.setValue((1-provider.getRTT_beta())*tcb.rttvar.getValue()+
                            provider.getRTT_beta()*Math.abs(tcb.srtt.getValue()-R),
                            comp.getSim().now(),provider.getLogFactor());
      tcb.srtt.setValue((1-provider.getRTT_alpha())*tcb.srtt.getValue() +
                        provider.getRTT_alpha()*R,comp.getSim().now(),provider.getLogFactor());
    }
    tcb.rto.setValue(Math.min(provider.getRTT_ubound(),
                Math.max(provider.getRTT_lbound(),tcb.srtt.getValue() +
                         K*tcb.rttvar.getValue())),comp.getSim().now(),provider.getLogFactor());
    tcb.retrans_timer.setTempo(tcb.rto.getValue());
    tcb.rtt_on=false;
  }

  private void retrans_timeout(SimEvent e) {
    TCB tcb=(TCB)e.getParams();
    tcb.retrans_timer.done(); //clear timer

    //existence check
    if(tcbs.get(tcb.key)==null) return;

    if(tcb.retrans_q.isEmpty()) { //nothing to send!
      System.out.println("Warning: RETRANS_TIMEOUT triggered without data in q");
      return;
    }

    //congestion window management
    tcb.ssthresh.setValue(Math.max((tcb.snd_nxt.getValue()-tcb.snd_una.getValue())/2,
                                    2*provider.getMaxSegmentSize()),comp.getSim().now(),provider.getLogFactor());
    if(tcb.fast_retrans_recovery==true) {
      tcb.cwnd.setValue(tcb.ssthresh.getValue()+3*provider.getMaxSegmentSize(),comp.getSim().now(),provider.getLogFactor());
    }
    else
      tcb.cwnd.setValue(provider.getMaxSegmentSize(),comp.getSim().now(),provider.getLogFactor());

    //retransmission timer management (double the RTO)
    tcb.rtt_on=false; //don't measure rtt when timeout
    tcb.rto.setValue(Math.min(provider.getRTT_ubound(),2*tcb.rto.getValue()),
                         comp.getSim().now(),provider.getLogFactor());
    tcb.retrans_timer.setTempo(tcb.rto.getValue());

    int max_to_send_offset = tcb.snd_una.getValue() + tcb.snd_wnd.getValue() - 1;
    int len = Math.min(provider.getMaxSegmentSize(),
                    max_to_send_offset - tcb.snd_una.getValue() + 1);

    // SH Added: allow at least one octet...
    len=Math.max(1,len);
    // SH end

    java.util.List payload=new java.util.LinkedList();
    boolean syn=false, fin=false, push=false;
    int buflen=0;
    java.util.Iterator i=tcb.retrans_q.iterator();
    while (buflen<len) {
      TCPBuffer buf=(TCPBuffer)i.next();
      if(buflen+buf.len>len) { //this buffer too big, chop it...
        //must add the first half in the retrans q
        TCPBuffer tempbuf=new TCPBuffer();
        tempbuf.len=len-buflen;
        payload.add(tempbuf);

        if(buf.push) push=true;
        break;
      }
      if(buf.syn) syn=true;
      else if(buf.fin) fin=true;
      else payload.add(buf.makeclone());

      buflen+=buf.len;
      if(buf.push) push=true;

      if(!i.hasNext()) { //all sent
        len=buflen;
        break;
      }
    }

    TCPSegment seg=new TCPSegment();
    seg.sourceport=tcb.key.source_port;
    seg.destport=tcb.key.dest_port;
    seg.seg_seq=tcb.snd_una.getValue();
    seg.seg_wnd=tcb.rcv_wnd.getValue();
    seg.syn=syn;
    seg.fin=fin;
    seg.psh=push;
    if(tcb.status.getValue()!=STAT_SYN_SENT) {
      seg.ack=true;
      seg.seg_ack=tcb.rcv_nxt.getValue();
    }
    seg.seg_len=len;
    seg.payload=payload;
    IPPacket packet=new IPPacket();
    packet.sourceIP=tcb.key.source_ip;
    packet.destIP=tcb.key.dest_ip;
    packet.protocol=IPPacket.PRO_TCP;
    packet.len=Math.max(46,40+len); //note: ip & tcp headers each 20 bytes
    packet.payload=seg;
    send_ip(packet);

    //restart timer
    tcb.retrans_timer.start();
  }

  private void timewait_timeout(SimEvent e) {
    TCB tcb=(TCB)e.getParams();
    tcb.timewait_timer.done(); //clear timer

    //existence check
    if(tcbs.get(tcb.key)==null) return;

    //say goodbye!
    tcb.status.setValue(STAT_CLOSED);
    tcbs.remove(tcb.key);
    tcb.user.notify(TCPUser.CON_TIMEWAIT_TIMEOUT,new Integer(tcb.key.source_port));
    provider.statusChanged();
  }

  private void transmit_packet(IPPacket packet) {
    provider.sendPacket(packet);    
  }

  private void process_packet(IPPacket packet,SimComponent fromlink) {
    TCPSegment seg=(TCPSegment)packet.payload;
    TCBKey k=new TCBKey(packet.destIP,seg.destport,packet.sourceIP,seg.sourceport);

    boolean passive=false;
    TCB tcb=(TCB)tcbs.get(k);

    if(tcb==null) { //if no active socket, try passive one
      passive=true;
      k=new TCBKey(packet.destIP,seg.destport,0,0);
      tcb=(TCB)tcbs.get(k);
    }

    if(tcb==null) { //ok, considered status CLOSED
      if(!seg.rst) { //reset bit not set, send back reset
        TCPSegment newseg=new TCPSegment();
        newseg.sourceport=seg.destport;
        newseg.destport=seg.sourceport;
        if(seg.ack) {
          newseg.seg_seq=seg.seg_ack;
          newseg.rst=true;
        }
        else {
          newseg.seg_seq=0;
          newseg.seg_ack=seg.seg_seq+seg.seg_len;
          newseg.ack=true;
          newseg.rst=true;
        }
        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);
      }
      return;
    }
    
    switch(tcb.status.getValue()) {
      case STAT_LISTEN:
        if(seg.rst) return;
        if(seg.ack) { //not accepting ack, send reset
          TCPSegment newseg=new TCPSegment();
          newseg.sourceport=seg.destport;
          newseg.destport=seg.sourceport;
          newseg.seg_seq=seg.seg_ack;
          newseg.rst=true;
          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);
          return;
        }

        if(seg.syn) {
          tcb.rcv_nxt.setValue(seg.seg_seq+1,comp.getSim().now(),provider.getLogFactor());
          tcb.irs.setValue(seg.seg_seq);
          tcb.iss.setValue(init_seq_generator(comp.getSim().now()));
          tcb.snd_una.setValue(tcb.iss.getValue(),comp.getSim().now(),provider.getLogFactor());
          tcb.snd_nxt.setValue(tcb.iss.getValue()+1,comp.getSim().now(),provider.getLogFactor());
          tcb.status.setValue(STAT_SYN_RCVD);

          // SH added: I think it's good to initialize these variables here
          tcb.snd_wl1.setValue(seg.seg_seq);
          tcb.snd_wl2.setValue(tcb.iss.getValue());
          // SH end

          TCPSegment newseg=new TCPSegment();
          newseg.sourceport=seg.destport;
          newseg.destport=seg.sourceport;
          newseg.seg_seq=tcb.iss.getValue();
          newseg.syn=true;
          newseg.ack=true;
          newseg.seg_ack=tcb.rcv_nxt.getValue();
          newseg.seg_wnd=tcb.rcv_wnd.getValue();
          newseg.seg_len=1;
          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.rtt_seq=tcb.iss.getValue(); //set the rtt reference seq num
          tcb.rtt_tick=comp.getSim().now();
          tcb.rtt_on=true;

          if(passive) { //change key now... (the original tcp.passive is not changed)
            tcbs.remove(tcb.key);
            tcb.key.source_ip=packet.destIP;
            tcb.key.source_port=seg.destport;
            tcb.key.dest_ip=packet.sourceIP;
            tcb.key.dest_port=seg.sourceport;
            tcbs.put(tcb.key,tcb);
          }

          //retrans q & timer
          TCPBuffer buf=new TCPBuffer();
          buf.syn=true;
          buf.len=1;
          tcb.retrans_q.add(buf);
          tcb.retrans_timer.start();

          provider.statusChanged();
        }

        return;

      case STAT_SYN_SENT:
        if(seg.ack) {
          if(modLE(seg.seg_ack,tcb.iss.getValue()) || modGT(seg.seg_ack,tcb.snd_nxt.getValue())) {
            if(!seg.rst) {
              TCPSegment newseg=new TCPSegment();
              newseg.sourceport=seg.destport;
              newseg.destport=seg.sourceport;
              newseg.seg_seq=seg.seg_ack;
              newseg.rst=true;
              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);
            }
            return;
          }
        }
        if(seg.rst) {
          if(seg.ack) {
            tcb.retrans_timer.stop(); //safety
            tcb.status.setValue(STAT_CLOSED);
            tcbs.remove(tcb.key);
            tcb.user.notify(TCPUser.CON_RESET,"error: connection reset");
            provider.statusChanged();
          }
          return;
        }
        if(seg.syn) {
          tcb.rcv_nxt.setValue(seg.seg_seq+1,comp.getSim().now(),provider.getLogFactor());
          tcb.irs.setValue(seg.seg_seq);
          if(seg.ack) {
            tcb.snd_una.setValue(seg.seg_ack,comp.getSim().now(),provider.getLogFactor());
            if(modGT(seg.seg_ack,tcb.iss.getValue())) {
              if(tcb.rtt_on && modLT(tcb.rtt_seq,tcb.snd_una.getValue())) updateRTT(tcb);
              tcb.retrans_q.clear(); //at most a SYN inside...
              tcb.retrans_timer.stop();
            }
          }

          // SH added: I think it's good to initialize these variables here
          tcb.snd_wl1.setValue(seg.seg_seq);
          tcb.snd_wl2.setValue(tcb.iss.getValue());
          // SH end

          if(modGT(tcb.snd_una.getValue(),tcb.iss.getValue())) {
            tcb.status.setValue(STAT_ESTABLISHED);

            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;

⌨️ 快捷键说明

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