RemCatpublic class RemCat extends Object
RemCat - remotely cat (DOS type) a file, using the TFTP protocol.
Inspired by the "rcat" exercise in Learning Tree Course 363,
UNIX Network Programming, by Dr. Chris Brown.
<[>
Note that the TFTP server is NOT "internationalized"; the name and
mode *in the protocol* are defined in terms of ASCII, not UniCode. |
Fields Summary |
---|
public static final int | TFTP_PORTThe UDP port number | protected final String | MODEThe mode we will use - octet for everything. | protected final int | OFFSET_REQUESTThe offset for the code/response as a byte | protected final int | OFFSET_PACKETNUMThe offset for the packet number as a byte | protected static boolean | debugDebugging flag | public final int | OP_RRQTFTP op-code for a read request | public final int | OP_WRQTFTP op-code for a read request | public final int | OP_DATATFTP op-code for a read request | public final int | OP_ACKTFTP op-code for a read request | public final int | OP_ERRORTFTP op-code for a read request | protected static final int | PACKET_SIZE | protected String | host | protected InetAddress | servAddr | protected DatagramSocket | sock | protected byte[] | buffer | protected DatagramPacket | inp | protected DatagramPacket | outp |
Constructors Summary |
---|
RemCat(String host)
super();
this.host = host;
servAddr = InetAddress.getByName(host);
sock = new DatagramSocket();
buffer = new byte[PACKET_SIZE];
outp = new DatagramPacket(buffer, PACKET_SIZE, servAddr, TFTP_PORT);
inp = new DatagramPacket(buffer, PACKET_SIZE);
|
Methods Summary |
---|
public static void | main(java.lang.String[] argv)The main program that drives this network client.
if (argv.length < 2) {
System.err.println("usage: rcat host filename[...]");
System.exit(1);
}
if (debug)
System.err.println("Java RemCat starting");
RemCat rc = new RemCat(argv[0]);
for (int i = 1; i<argv.length; i++) {
if (debug)
System.err.println("-- Starting file " +
argv[0] + ":" + argv[i] + "---");
rc.readFile(argv[i]);
}
| void | readFile(java.lang.String path)
buffer[0] = 0;
buffer[OFFSET_REQUEST] = OP_RRQ; // read request
int p = 2; // number of chars into buffer
// Convert filename String to bytes in buffer , using "p" as an
// offset indicator to get all the bits of this request
// in exactly the right spot.
byte[] bTemp = path.getBytes(); // i.e., ASCII
System.arraycopy(bTemp, 0, buffer, p, path.length());
p += path.length();
buffer[p++] = 0; // null byte terminates string
// Similarly, convert MODE ("stream" or "octet") to bytes in buffer
bTemp = MODE.getBytes(); // i.e., ASCII
System.arraycopy(bTemp, 0, buffer, p, MODE.length());
p += MODE.length();
buffer[p++] = 0; // null terminate
/* Send Read Request to tftp server */
outp.setLength(p);
sock.send(outp);
/* Loop reading data packets from the server until a short
* packet arrives; this indicates the end of the file.
*/
int len = 0;
do {
sock.receive(inp);
if (debug)
System.err.println(
"Packet # " + Byte.toString(buffer[OFFSET_PACKETNUM])+
"RESPONSE CODE " + Byte.toString(buffer[OFFSET_REQUEST]));
if (buffer[OFFSET_REQUEST] == OP_ERROR) {
System.err.println("rcat ERROR: " +
new String(buffer, 4, inp.getLength()-4));
return;
}
if (debug)
System.err.println("Got packet of size " +
inp.getLength());
/* Print the data from the packet */
System.out.write(buffer, 4, inp.getLength()-4);
/* Ack the packet. The block number we
* want to ack is already in buffer so
* we just change the opcode. The ACK is
* sent to the port number which the server
* just sent the data from, NOT to port
* TFTP_PORT.
*/
buffer[OFFSET_REQUEST] = OP_ACK;
outp.setLength(4);
outp.setPort(inp.getPort());
sock.send(outp);
} while (inp.getLength() == PACKET_SIZE);
if (debug)
System.err.println("** ALL DONE** Leaving loop, last size " +
inp.getLength());
|
|