in src/main/java/org/apache/commons/net/tftp/TFTPClient.java [291:402]
public void sendFile(final String fileName, final int mode, InputStream input, InetAddress host, final int port) throws IOException {
int block = 0;
int hostPort = 0;
boolean justStarted = true;
boolean lastAckWait = false;
totalBytesSent = 0L;
if (mode == TFTP.ASCII_MODE) {
input = new ToNetASCIIInputStream(input);
}
TFTPPacket sent = new TFTPWriteRequestPacket(host, port, fileName, mode);
final TFTPDataPacket data = new TFTPDataPacket(host, port, 0, sendBuffer, 4, 0);
beginBufferedOps();
try {
do { // until eof
// first time: block is 0, lastBlock is 0, send a request packet.
// subsequent: block is integer starting at 1, send data packet.
bufferedSend(sent);
boolean wantReply = true;
int timeouts = 0;
do {
try {
final TFTPPacket received = bufferedReceive();
final InetAddress recdAddress = received.getAddress();
final int recdPort = received.getPort();
// The first time we receive we get the port number and
// answering host address (for hosts with multiple IPs)
if (justStarted) {
justStarted = false;
if (recdPort == port) { // must not use the control port here
final TFTPErrorPacket error = new TFTPErrorPacket(recdAddress, recdPort, TFTPErrorPacket.UNKNOWN_TID, "INCORRECT SOURCE PORT");
bufferedSend(error);
throw new IOException("Incorrect source port (" + recdPort + ") in request reply.");
}
hostPort = recdPort;
data.setPort(hostPort);
if (!host.equals(recdAddress)) {
host = recdAddress;
data.setAddress(host);
sent.setAddress(host);
}
}
// Comply with RFC 783 indication that an error acknowledgment
// should be sent to originator if unexpected TID or host.
if (host.equals(recdAddress) && recdPort == hostPort) {
switch (received.getType()) {
case TFTPPacket.ERROR:
final TFTPErrorPacket error = (TFTPErrorPacket) received;
throw new IOException("Error code " + error.getError() + " received: " + error.getMessage());
case TFTPPacket.ACKNOWLEDGEMENT:
final int lastBlock = ((TFTPAckPacket) received).getBlockNumber();
if (lastBlock == block) {
++block;
if (block > 65535) {
// wrap the block number
block = 0;
}
wantReply = false; // got the ack we want
} else {
discardPackets();
}
break;
default:
throw new IOException("Received unexpected packet type.");
}
} else { // wrong host or TID; send error
final TFTPErrorPacket error = new TFTPErrorPacket(recdAddress, recdPort, TFTPErrorPacket.UNKNOWN_TID, "Unexpected host or port.");
bufferedSend(error);
}
} catch (final SocketException | InterruptedIOException e) {
if (++timeouts >= maxTimeouts) {
throw new IOException("Connection timed out.");
}
} catch (final TFTPPacketException e) {
throw new IOException("Bad packet: " + e.getMessage());
}
// retry until a good ack
} while (wantReply);
if (lastAckWait) {
break; // we were waiting for this; now all done
}
int dataLength = TFTPPacket.SEGMENT_SIZE;
int offset = 4;
int totalThisPacket = 0;
int bytesRead = 0;
while (dataLength > 0 && (bytesRead = input.read(sendBuffer, offset, dataLength)) > 0) {
offset += bytesRead;
dataLength -= bytesRead;
totalThisPacket += bytesRead;
}
if (totalThisPacket < TFTPPacket.SEGMENT_SIZE) {
/* this will be our last packet -- send, wait for ack, stop */
lastAckWait = true;
}
data.setBlockNumber(block);
data.setData(sendBuffer, 4, totalThisPacket);
sent = data;
totalBytesSent += totalThisPacket;
} while (true); // loops until after lastAckWait is set
} finally {
endBufferedOps();
}
}