📄 tcp.java
字号:
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 + -