You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
264 lines
10 KiB
Java
264 lines
10 KiB
Java
// TFTPSender.java (C) K. J. Turner, K. A. Whyte 05/06/01
|
|
|
|
// Trivial File Transfer Protocol sender (client)
|
|
|
|
package protocol; // protocol package
|
|
|
|
import java.util.Vector; // vector (list)
|
|
import support.*; // protocol entity support
|
|
|
|
/**
|
|
This is the class for a Trivial File Transfer Protocol sender.
|
|
|
|
@author Kenneth J. Turner, Kenneth A. Whyte
|
|
@version 1.0 (5th June 2001, KAW): initial version
|
|
<br/> 1.4 (9th March 2006, KJT): updated for JDK 1.5
|
|
<br/> 1.5 (27th July 2010, KJT): unchecked warning suppressed
|
|
*/
|
|
public class TFTPSender // protocol sender (client)
|
|
implements ProtocolEntity, Timeouts { // protocol entity, timeout
|
|
|
|
// simulator variables
|
|
|
|
private ProtocolEntity peer; // peer entity (server)
|
|
private Medium medium; // communications medium
|
|
private String name; // entity name
|
|
|
|
// protocol variables
|
|
|
|
private int pduNo; // PDU seq number sent/expected
|
|
private PDU pduReceived; // PDU received
|
|
private PDU pduSent; // PDU sent
|
|
private boolean timerEnabled; // whether timer is enabled
|
|
private float errorProb = 0.8f; // file I/O error probability
|
|
private int fileNo; // file number to transfer
|
|
|
|
// protocol state
|
|
|
|
int state; // current protocol state
|
|
|
|
final static int idle = 0; // no connection
|
|
final static int readRequest = 1; // file to be read
|
|
final static int reading = 2; // reading data
|
|
final static int writeRequest = 3; // file to be written
|
|
final static int writing = 4; // writing data
|
|
final static int waitLast = 5; // wait for last re-send
|
|
|
|
// protocol messages
|
|
|
|
final static String ack = "ACK"; // acknowledgement message type
|
|
final static String data = "DATA"; // data message type
|
|
final static String error = "ERROR"; // error message type
|
|
final static String rrq = "RRQ"; // read request message type
|
|
final static String wrq = "WRQ"; // write request messagetype
|
|
|
|
// protocol methods
|
|
|
|
public TFTPSender(Medium m, String name) { // construct sender instance
|
|
this.name = name; // set protocol entity name
|
|
medium = m; // set underlying medium
|
|
initialise (); // initialise protocol
|
|
}
|
|
|
|
public String getName () { // get protocol entity name
|
|
return((name)); // return protocol entity name
|
|
}
|
|
|
|
public Vector<String> getServices() { // get protocol entity services
|
|
Vector<String> events = // list of events
|
|
new Vector<String>();
|
|
String pduType; // received PDU type
|
|
int pduSeq; // received PDU seq number
|
|
|
|
if (pduReceived != null) { // PDU received?
|
|
pduType = pduReceived.type; // get received PDU type
|
|
pduSeq = pduReceived.seq; // get received PDU seq number
|
|
if ((state == readRequest || // read request or ...
|
|
state == reading || // reading or ...
|
|
state == waitLast) && // awaiting re-send, and ...
|
|
pduType.equals(data)) { // data message?
|
|
if (pduSeq == pduNo) { // expected sequence number?
|
|
timerEnabled = false; // cancel timeout
|
|
events.addElement( // send acknowledgement
|
|
ack + "(" + pduNo + ") - send acknowledgement");
|
|
}
|
|
else if (state == readRequest) // wrong sequence, read req?
|
|
events.addElement( // report seq number error
|
|
error +"(wrong data sequence number) - report error");
|
|
}
|
|
else if ((state == writeRequest || // write request or
|
|
state == writing) && // writing, and ...
|
|
pduType.equals(ack)) { // write and acknowledgement?
|
|
if (pduSeq == pduNo) { // expected sequence number?
|
|
timerEnabled = false; // cancel timeout
|
|
if (pduSent != null && // valid previous PDU and ...
|
|
pduSent.sdu.equals("Dlast")) // last data sent?
|
|
reinitialise(); // re-initialise protocol
|
|
else { // more data to send
|
|
events.addElement( // send data
|
|
data + "(" + (pduNo + 1) + ",D" + pduNo + ") - send data");
|
|
events.addElement( // send last data
|
|
data + "(" + (pduNo + 1) + ",Dlast) - send last data");
|
|
}
|
|
}
|
|
else if (state == writing && // writing and ...
|
|
pduSeq == pduNo - 1) // repeated acknowledgement?
|
|
events.addElement( // send data
|
|
data + "(" + pduSent.seq + "," + pduSent.sdu + ") - re-send data");
|
|
else if (state == writeRequest) // wrong sequence, write req?
|
|
events.addElement( // report seq number error
|
|
error +"(wrong acknowledgement sequence number) - report error");
|
|
}
|
|
else if (pduType.equals(error)) { // error message?
|
|
state = idle; // back to not connected
|
|
}
|
|
}
|
|
if (state == idle) { // not connected?
|
|
events.addElement( // read file
|
|
rrq + "(file" + fileNo + ") - ask to read file");
|
|
events.addElement( // write file
|
|
wrq + "(file" + fileNo +") - ask to write file");
|
|
}
|
|
if (state == waitLast) // waiting for last re-send?
|
|
events.addElement( // add close event
|
|
"Close - presume all retransmissions over");
|
|
if (state == writing && // writing and ...
|
|
pduSent != null && // PDU was sent and ...
|
|
!pduSent.sdu.equals("Dlast") && // PDU was not last and ...
|
|
TFTPMedium.random() < errorProb) // file I/O error occurs?
|
|
events.addElement( // report I/O error
|
|
error +"(data for write unavailable) - report error");
|
|
if (timerEnabled) // timer is enabled?
|
|
events.addElement( // add timeout event
|
|
"Timeout - presume loss of message and resend");
|
|
return(events); // return list of events
|
|
}
|
|
|
|
public boolean hasTimer(String type) { // PDU needs timer?
|
|
return((true)); // report it does
|
|
}
|
|
|
|
public void initialise () { // initialise protocol
|
|
fileNo = 0; // initialise file number
|
|
reinitialise(); // re-initialise protocol
|
|
}
|
|
|
|
public Vector<ProtocolEvent> performService (String s) { // protocol service
|
|
Vector<ProtocolEvent> events = // initialise events list
|
|
new Vector<ProtocolEvent>();
|
|
int start, middle, end; // start/middle/end subscripts
|
|
int pduSeq; // PDU sequence number
|
|
String pduData; // PDU data
|
|
|
|
if (s.startsWith (rrq)) { // send read request?
|
|
start = s.indexOf ('(') + 1; // get filename start
|
|
end = s.indexOf (')'); // get filename finish
|
|
pduData = s.substring(start, end); // get filename
|
|
transmitPDU( // send read request
|
|
new TFTPMessage(rrq , pduData), peer);
|
|
pduNo = 1; // expect seq number 1
|
|
state = readRequest; // now requested write
|
|
}
|
|
else if (s.startsWith (ack)) { // send acknowledgement?
|
|
start = s.indexOf ('(') + 1; // get seq number start
|
|
end = s.indexOf (')'); // get seq number end
|
|
pduSeq = // get sequence number
|
|
Integer.parseInt(s.substring(start, end));
|
|
if (pduReceived != null && // valid PDU received and ...
|
|
pduReceived.sdu.equals("Dlast")) // last data?
|
|
state = waitLast; // wait for last re-send
|
|
else { // still reading
|
|
pduNo++; // to next sequence number
|
|
state = reading; // (now) reading
|
|
}
|
|
transmitPDU( // send acknowledgement
|
|
new TFTPMessage(ack, pduSeq), peer);
|
|
}
|
|
else if (s.startsWith (wrq)) { // send write request?
|
|
start = s.indexOf ('(') + 1; // get filename start
|
|
end = s.indexOf (')'); // get filename finish
|
|
pduData = s.substring(start, end); // get filename
|
|
transmitPDU( // send write request
|
|
new TFTPMessage(wrq , pduData), peer);
|
|
state = writeRequest; // now requested write
|
|
}
|
|
else if (s.startsWith (data)) { // send data?
|
|
start = s.indexOf ('(') + 1; // get seq number start
|
|
middle = s.indexOf (','); // get comma position
|
|
end = s.indexOf (')'); // get seq number end
|
|
pduSeq = // get sequence number
|
|
Integer.parseInt(s.substring(start, middle));
|
|
pduData = // get data content
|
|
s.substring(middle + 1, end);
|
|
transmitPDU( // send data
|
|
new TFTPMessage(data, pduSeq, pduData), peer);
|
|
pduNo++; // to next sequence number
|
|
state = writing; // (now) writing
|
|
}
|
|
else if (s.startsWith (error)) { // send error?
|
|
start = s.indexOf ('(') + 1; // get error message start
|
|
end = s.indexOf (')'); // get error message end
|
|
pduData = s.substring(start, end); // get error message
|
|
transmitPDU( // send error
|
|
new TFTPMessage(error, pduData), peer);
|
|
state = waitLast; // wait for last re-send
|
|
}
|
|
else if (s.startsWith ("Close")) { // close?
|
|
events.addElement( // add closed comment
|
|
new ProtocolEvent(ProtocolEvent.COMMENT, this, "Closed"));
|
|
reinitialise(); // re-initialise protocol
|
|
}
|
|
if (s.startsWith ("Timeout")) { // timeout?
|
|
transmitPDU(pduSent, peer); // re-send PDU
|
|
events.addElement( // add timeout event and PDU
|
|
new ProtocolEvent(ProtocolEvent.TIMEOUT, pduSent));
|
|
}
|
|
else if (pduSent != null) // PDU to send?
|
|
events.addElement( // transmit PDU
|
|
new ProtocolEvent(ProtocolEvent.TRANSMIT, pduSent));
|
|
return(events); // return list of events
|
|
}
|
|
|
|
public Vector<ProtocolEvent> receivePDU(PDU pdu) { // handle received PDU
|
|
pduReceived = pdu; // store PDU
|
|
if (pduReceived.type.equals(error)) // error message?
|
|
reinitialise(); // re-initialise protocol
|
|
return((new Vector<ProtocolEvent>())); // return no events
|
|
}
|
|
|
|
public void reinitialise() { // re-initialise protocol
|
|
state = idle; // initialise state
|
|
pduNo = 0; // initialise seq number
|
|
pduReceived = null; // initialise no PDU received
|
|
pduSent = null; // initialise no PDU sent
|
|
timerEnabled = false; // initialise no timeout
|
|
fileNo++; // to next file number
|
|
}
|
|
|
|
public void setPeer(ProtocolEntity peer) { // set protocol peer
|
|
this.peer = peer; // set this entity's peer
|
|
}
|
|
|
|
/**
|
|
Set the timer for a specified PDU.
|
|
|
|
@param pdu PDU
|
|
@param enabled whether the timer is enabled
|
|
*/
|
|
public void setTimer(PDU pdu, boolean enabled) { // set timer status
|
|
if (state != idle) // not idle?
|
|
timerEnabled = enabled; // store timer status
|
|
}
|
|
|
|
public void transmitPDU( // transmit PDU
|
|
PDU pdu, ProtocolEntity dest) { // for given PDU, destination
|
|
pdu.setSource (this); // source is this entity
|
|
pdu.setDestination(dest); // destination is as given
|
|
pduSent = pdu; // copy PDU sent
|
|
medium.receivePDU(pdu); // medium receives PDU
|
|
pduReceived = null; // note no PDU in response
|
|
timerEnabled = false; // note no timeout
|
|
}
|
|
|
|
}
|