I'm trying to write a BOOTP Client/Server in Java, and one of the specifications in the RFC is that the client can write the nickname of the server it wants to connect to. If the packet reaches a server that is not the one specified, it should discard the bootrequest.
I have three classes (BOOTPClient, BOOTPServer and BOOTPMessage). As of now, I've successfully sent the bootrequest from the client to the server, who recieves it and starts to process it.
The problem is here:
String sname = new String(btpmsg.getSname());
String serverName = args[0];
boolean discard = false;
System.out.println("|"+serverName+"|"+sname+"|");
if (!sname.equalsIgnoreCase("") && !sname.equalsIgnoreCase(serverName)) {
discard = true;
System.out.println("The request was not for this server. Server requested: "+sname);
}
This meaning: if the string is not null (in which case we don't care about what server it arrives to), make sure it's the correct server. As you can see, I printed both strings between "|" to be 100% sure that there aren't whitespaces or anything that could mess up the comparison. Yet, it enters into if block and executes the sentences inside. It happens both if the string is the same as the server name and if it's blank.
To clarify: btpmsg is an instance of the BOOTPMsg class, the server name is stored as an array of bytes (everything is coded into a byte array with ByteArrayOutputStream to send it with DatagramPacket) and then converted to a String. I don't know where the problem may be.
A sample of the output:
Server (called with "java BOOTPServer bootpserver"):
Server bootpserver running. Awaiting requests.
Bootrequest received.
|bootpserver|bootpserver|
The request was not for this server. Server requested: bootpserver
Client:
Enter your IP if known. Otherwise, press enter.
Enter the IP of the server if known. Otherwise, press enter.
Enter the name of the server if known. Otherwise, press enter.
bootpserver
Enter the file name if known. Otherwise, press enter.
I'd appreciate any help, because I don't know what else I can look for errors. My best bet was on using the "write" method on ByteArrayOutputStream or readFully in DataInputStream, but all others parameters work fine. Thanks a lot in advance.
Your getSname()
method returns a byte[]
of fixed length 64, which is the specified length of the sname
field in the BOOTP protocol. When you pass it directly to the String(byte[])
constructor, you get a string right-padded to length 64 with zero-characters.
To fix this, you need to find the first zero byte in the array and use that when constructing the string. Additionally make sure you pass in an explicit character encoding; otherwise you are at the mercy of the platform default.
So, use code such as this:
sname2string(byte[] sname) {
int length = 0;
while (length < 64 && sname[length] != 0) length++;
return new String(sname, 0, length, StandardCharsets.ISO_8859_1);
}