/** * * Requests to send a file to a remote host, reads the file from an InputStream, sends the file * to the remote host, and closes the connection. A local UDP socket must first be created by <a * href="org.apache.commons.net.DatagramSocketClient.html#open">open()</a> before invoking this * method. This method will not close the InputStream containing the file; you must close it after * the method invocation. * * <p> * * @param filename The name the remote server should use when creating the file on its file * system. * @param mode The TFTP mode of the transfer (one of the MODE constants). * @param host The remote host receiving the file. * @param port The port number of the remote TFTP server. * @exception IOException If an I/O error occurs. The nature of the error will be reported in the * message. * */ public void sendFile(String filename, int mode, InputStream input, InetAddress host, int port) throws IOException { int bytesRead, timeouts, lastBlock, block, hostPort, dataLength, offset; TFTPPacket sent, received = null; TFTPErrorPacket error; TFTPDataPacket data = new TFTPDataPacket(host, port, 0, _sendBuffer, 4, 0); ; TFTPAckPacket ack; beginBufferedOps(); dataLength = lastBlock = hostPort = bytesRead = 0; block = 0; if (mode == TFTP.ASCII_MODE) input = new ToNetASCIIInputStream(input); sent = new TFTPWriteRequestPacket(host, port, filename, mode); _sendPacket: do { bufferedSend(sent); _receivePacket: while (true) { timeouts = 0; while (timeouts < __maxTimeouts) { try { received = bufferedReceive(); break; } catch (SocketException e) { if (++timeouts >= __maxTimeouts) { endBufferedOps(); throw new IOException("Connection timed out."); } continue; } catch (InterruptedIOException e) { if (++timeouts >= __maxTimeouts) { endBufferedOps(); throw new IOException("Connection timed out."); } continue; } catch (TFTPPacketException e) { endBufferedOps(); throw new IOException("Bad packet: " + e.getMessage()); } } // The first time we receive we get the port number and // answering host address (for hosts with multiple IPs) if (lastBlock == 0) { hostPort = received.getPort(); data.setPort(hostPort); if (!host.equals(received.getAddress())) { host = received.getAddress(); data.setAddress(host); sent.setAddress(host); } } // Comply with RFC 783 indication that an error acknowledgement // should be sent to originator if unexpected TID or host. if (host.equals(received.getAddress()) && received.getPort() == hostPort) { switch (received.getType()) { case TFTPPacket.ERROR: error = (TFTPErrorPacket) received; endBufferedOps(); throw new IOException( "Error code " + error.getError() + " received: " + error.getMessage()); case TFTPPacket.ACKNOWLEDGEMENT: ack = (TFTPAckPacket) received; lastBlock = ack.getBlockNumber(); if (lastBlock == block) { ++block; break _receivePacket; } else { discardPackets(); if (lastBlock == (block - 1)) continue _sendPacket; // Resend last acknowledgement. continue _receivePacket; // Start fetching packets again. } // break; default: endBufferedOps(); throw new IOException("Received unexpected packet type."); } } else { error = new TFTPErrorPacket( received.getAddress(), received.getPort(), TFTPErrorPacket.UNKNOWN_TID, "Unexpected host or port."); bufferedSend(error); continue _sendPacket; } // We should never get here, but this is a safety to avoid // infinite loop. If only Java had the goto statement. // break; } dataLength = TFTPPacket.SEGMENT_SIZE; offset = 4; while (dataLength > 0 && (bytesRead = input.read(_sendBuffer, offset, dataLength)) > 0) { offset += bytesRead; dataLength -= bytesRead; } data.setBlockNumber(block); data.setData(_sendBuffer, 4, offset - 4); sent = data; } while (dataLength == 0); bufferedSend(sent); endBufferedOps(); }
/** * * Requests a named file from a remote host, writes the file to an OutputStream, closes the * connection, and returns the number of bytes read. A local UDP socket must first be created by * <a href="org.apache.commons.net.DatagramSocketClient.html#open">open()</a> before invoking this * method. This method will not close the OutputStream containing the file; you must close it * after the method invocation. * * <p> * * @param filename The name of the file to receive. * @param mode The TFTP mode of the transfer (one of the MODE constants). * @param output The OutputStream to which the file should be written. * @param host The remote host serving the file. * @param port The port number of the remote TFTP server. * @exception IOException If an I/O error occurs. The nature of the error will be reported in the * message. * */ public int receiveFile(String filename, int mode, OutputStream output, InetAddress host, int port) throws IOException { int bytesRead, timeouts, lastBlock, block, hostPort, dataLength; TFTPPacket sent, received = null; TFTPErrorPacket error; TFTPDataPacket data; TFTPAckPacket ack = new TFTPAckPacket(host, port, 0); beginBufferedOps(); dataLength = lastBlock = hostPort = bytesRead = 0; block = 1; if (mode == TFTP.ASCII_MODE) output = new FromNetASCIIOutputStream(output); sent = new TFTPReadRequestPacket(host, port, filename, mode); _sendPacket: do { bufferedSend(sent); _receivePacket: while (true) { timeouts = 0; while (timeouts < __maxTimeouts) { try { received = bufferedReceive(); break; } catch (SocketException e) { if (++timeouts >= __maxTimeouts) { endBufferedOps(); throw new IOException("Connection timed out."); } continue; } catch (InterruptedIOException e) { if (++timeouts >= __maxTimeouts) { endBufferedOps(); throw new IOException("Connection timed out."); } continue; } catch (TFTPPacketException e) { endBufferedOps(); throw new IOException("Bad packet: " + e.getMessage()); } } // The first time we receive we get the port number and // answering host address (for hosts with multiple IPs) if (lastBlock == 0) { hostPort = received.getPort(); ack.setPort(hostPort); if (!host.equals(received.getAddress())) { host = received.getAddress(); ack.setAddress(host); sent.setAddress(host); } } // Comply with RFC 783 indication that an error acknowledgement // should be sent to originator if unexpected TID or host. if (host.equals(received.getAddress()) && received.getPort() == hostPort) { switch (received.getType()) { case TFTPPacket.ERROR: error = (TFTPErrorPacket) received; endBufferedOps(); throw new IOException( "Error code " + error.getError() + " received: " + error.getMessage()); case TFTPPacket.DATA: data = (TFTPDataPacket) received; dataLength = data.getDataLength(); lastBlock = data.getBlockNumber(); if (lastBlock == block) { try { output.write(data.getData(), data.getDataOffset(), dataLength); } catch (IOException e) { error = new TFTPErrorPacket( host, hostPort, TFTPErrorPacket.OUT_OF_SPACE, "File write failed."); bufferedSend(error); endBufferedOps(); throw e; } ++block; break _receivePacket; } else { discardPackets(); if (lastBlock == (block - 1)) continue _sendPacket; // Resend last acknowledgement. continue _receivePacket; // Start fetching packets again. } // break; default: endBufferedOps(); throw new IOException("Received unexpected packet type."); } } else { error = new TFTPErrorPacket( received.getAddress(), received.getPort(), TFTPErrorPacket.UNKNOWN_TID, "Unexpected host or port."); bufferedSend(error); continue _sendPacket; } // We should never get here, but this is a safety to avoid // infinite loop. If only Java had the goto statement. // break; } ack.setBlockNumber(lastBlock); sent = ack; bytesRead += dataLength; } // First data packet less than 512 bytes signals end of stream. while (dataLength == TFTPPacket.SEGMENT_SIZE); bufferedSend(sent); endBufferedOps(); return bytesRead; }