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