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

// 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
}
}