/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.net.ipv4.tftp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import org.apache.commons.net.tftp.TFTP;
import org.apache.commons.net.tftp.TFTPAckPacket;
import org.apache.commons.net.tftp.TFTPDataPacket;
import org.apache.commons.net.tftp.TFTPErrorPacket;
import org.apache.commons.net.tftp.TFTPPacket;
import org.apache.commons.net.tftp.TFTPPacketException;
import org.apache.commons.net.tftp.TFTPReadRequestPacket;
import org.apache.commons.net.tftp.TFTPWriteRequestPacket;
import org.apache.log4j.Logger;
/**
* TFTP server. Currently only supports one client at a time.
*
* @author markhale
*/
public class TFTPServer extends TFTP {
private static final Logger log = Logger.getLogger(TFTPServer.class);
/** current client address */
private InetAddress clientAddress;
private int clientPort;
/** send transfer stream */
private FileInputStream fileIn;
/** receive transfer stream */
private FileOutputStream fileOut;
/** current block number received or sent */
private int blockNumber;
public static void main(String[] args) {
TFTPServer server = new TFTPServer();
try {
server.run();
} catch (SocketException ex) {
Logger.getLogger(TFTPServer.class).fatal("Socket exception", ex);
}
}
private void run() throws SocketException {
System.out.println("JNode TFTP Server");
open(DEFAULT_PORT);
setSoTimeout(0);
beginBufferedOps();
try {
boolean doShutdown = false;
while (!doShutdown) {
try {
TFTPPacket packet = bufferedReceive();
processRequest(packet);
} catch (TFTPPacketException ex) {
log.debug("Error in TFTP packet", ex);
} catch (IOException ex) {
log.debug("I/O exception", ex);
}
}
} finally {
endBufferedOps();
close();
}
}
private void processRequest(TFTPPacket packet) throws IOException {
if (log.isDebugEnabled())
log.debug("Received packet: " + packet.getAddress() + ':' + packet.getPort());
final int type = packet.getType();
switch (type) {
case TFTPPacket.WRITE_REQUEST:
if (clientAddress == null) {
TFTPWriteRequestPacket wreqPacket = (TFTPWriteRequestPacket) packet;
File file = new File(".", wreqPacket.getFilename());
log.info("Request to write file " + wreqPacket.getFilename() + " (" +
file.getAbsolutePath() + ") received from " + packet.getAddress() +
':' + packet.getPort());
fileOut = new FileOutputStream(file);
blockNumber = 0;
bufferedSend(new TFTPAckPacket(packet.getAddress(), packet.getPort(), blockNumber));
clientAddress = packet.getAddress();
clientPort = packet.getPort();
}
break;
case TFTPPacket.DATA:
if (packet.getAddress().equals(clientAddress) && packet.getPort() == clientPort) {
TFTPDataPacket dataPacket = (TFTPDataPacket) packet;
// if client sent next block
if (dataPacket.getBlockNumber() == blockNumber + 1) {
fileOut.write(dataPacket.getData(), dataPacket.getDataOffset(), dataPacket
.getDataLength());
// send acknowledgement
bufferedSend(new TFTPAckPacket(packet.getAddress(), packet.getPort(),
dataPacket.getBlockNumber()));
blockNumber++;
// if last block then end of transfer
if (dataPacket.getDataLength() < TFTPDataPacket.MAX_DATA_LENGTH) {
clientAddress = null;
clientPort = 0;
fileOut.close();
}
}
}
break;
case TFTPPacket.READ_REQUEST:
if (clientAddress == null) {
TFTPReadRequestPacket rreqPacket = (TFTPReadRequestPacket) packet;
try {
File file = new File(".", rreqPacket.getFilename());
log.info("Request to read file " + rreqPacket.getFilename() + " (" +
file.getAbsolutePath() + ") received from " + packet.getAddress() +
':' + packet.getPort());
fileIn = new FileInputStream(file);
blockNumber = 1;
byte[] data = new byte[TFTPDataPacket.MAX_DATA_LENGTH];
final int bytesRead = fileIn.read(data);
bufferedSend(new TFTPDataPacket(packet.getAddress(), packet.getPort(),
blockNumber, data, 0, bytesRead));
// if more blocks to send
if (bytesRead == TFTPDataPacket.MAX_DATA_LENGTH) {
clientAddress = packet.getAddress();
clientPort = packet.getPort();
} else {
fileIn.close();
}
} catch (FileNotFoundException ex) {
bufferedSend(new TFTPErrorPacket(packet.getAddress(), packet.getPort(),
TFTPErrorPacket.FILE_NOT_FOUND, ex.getMessage()));
}
}
break;
case TFTPPacket.ACKNOWLEDGEMENT:
if (packet.getAddress().equals(clientAddress) && packet.getPort() == clientPort) {
TFTPAckPacket ackPacket = (TFTPAckPacket) packet;
// if client acknowledged last block
if (ackPacket.getBlockNumber() == blockNumber) {
// send next block
byte[] data = new byte[TFTPDataPacket.MAX_DATA_LENGTH];
final int bytesRead = fileIn.read(data);
blockNumber++;
bufferedSend(new TFTPDataPacket(packet.getAddress(), packet.getPort(),
blockNumber, data, 0, bytesRead));
// if last block then end of transfer
if (bytesRead < TFTPDataPacket.MAX_DATA_LENGTH) {
clientAddress = null;
clientPort = 0;
fileIn.close();
}
}
}
break;
}
}
}