Rcon Java Class for Call of Duty: Black Ops
I've been playing all of Duty Black Ops for a while now and eventually rented my own server. As you probably know, RCON is the standard these days for Call of Duty games. It's been used in all the Call of Duty games to date and Black ops is no different.
Basically, RCON is just utilizes a specifically formatted UDP packet to send remote commands to your server. These commands give you the ability to see who is in your server, what their score is... kick people, ban people, change maps, set playlists, etc...
Since the introduction of Rcon, people have written numerous apps to make it easy to manage your servers via remote GUI. 99.9% of the time, these apps are written in Visual Basic. I don't have anything against VB, it is a fun language, but it isn't very portable (and by "isn't very", I mean "it is not").
My most recent Rcon app of choice was BlackTomatoMod. It has all the basics and tons more. The problem with BlackTOmatoMod, however, is that the author is inaccessible and does not help with issues in the forums. He no longer really supports it and wont release the source... so it will be gone soon enough. There are plenty of other choices (existing and future) for Rcon GUIs.
I had the idea to create a web based Rcon tool to get rid of the platform compatibility issues as well as the need to have a machine running your app 24/7 to monitor and manage your server.
Being a ColdFusion developer, I'm sure you know what my choice of language was for the core API... Yes, Java.
I was VERY surprised when I searched for a Java class for sending Rcon commands and only found very old, outdated code out there! The code examples that I was able to find hadn't worked with any newer games in years.
I started out trying to modify one just to get it into a workable state but, in the end, I was putting more time in modifying it that I would have put into writing a new one... so that's what I did.
I pulled out Wireshark and started reviewing UDP packets that the other VB apps were sending. Eventually, I figured out the payload structure that the BlackOps server expected and then I was in business.
So enough babbling... below is the most recent code for the core Java Rcon API (deemed NetRcon). I'd love to see some Java apps that can run on more than just Windows and hopefully this can get someone started on just that.
I still plan on trying to get some kind of basic web based Rcon tool up and running but it would be just the basics. To monitor chat and to get constant player status updates probably wouldn't do too well as a web app. It'd probably be fine for a couple servers but the more servers, the more constant UDP traffic the server would have to send/receive.
Anyway... like I said... here's the code.
import java.io.IOException;
import java.net.InetAddress;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class NetRcon
{
private InetAddress ipAddress;
private int port;
private int receiveTimeout;
private int sleepTimer;
private boolean returnsData;
private String password;
private String command;
private String retStr;
private DatagramPacket dataPacketOut;
private DatagramPacket dataPacketIn;
public NetRcon(String ip, int port, String password, boolean returnsData, int receiveTimeout, int sleepTimer) throws IOException
{
this.port = port;
this.password = password;
this.returnsData = returnsData;
this.receiveTimeout = receiveTimeout;
this.sleepTimer = sleepTimer;
parseAddress(ip);
}
public void sleeper() throws InterruptedException
{
Thread.sleep(sleepTimer);
}
private void parseAddress(String ip) throws IOException
{
ipAddress = InetAddress.getByName(ip);
System.out.println(ipAddress);
}
public DatagramPacket buildPacket(String rconCommand) throws IOException
{
// Build the command string to be sent
// The leading Xs are place holders for out of bounds bytes that will be converted once we get the java bytes for the string
command = "xxxxx" + password + " " + rconCommand;
// Convert the command string to bytes
byte[] commandBytes = command.getBytes();
// Replace the first 5 bytes (those leading Xs) in the commandBytes with the correct bytes
commandBytes[0] = (byte)0xff;
commandBytes[1] = (byte)0xff;
commandBytes[2] = (byte)0xff;
commandBytes[3] = (byte)0xff;
commandBytes[4] = (byte)0x00;
// Build the UDP packet that is to be sent
dataPacketOut = new DatagramPacket(commandBytes, commandBytes.length, ipAddress, port);
return dataPacketOut;
}
public String sendCommand(String rconCommand) throws InterruptedException
{
try{
// Create a new DatagramSocket instance
DatagramSocket dataSocket = new DatagramSocket(null);
// Connect the new datagramSocket instance to the provided ipAddress and port
dataSocket.connect(ipAddress, port);
// Set the timeout of the socket connection; TODO: parameterize the timeout value.
dataSocket.setSoTimeout(receiveTimeout);
// Send the packet (rcon command) to the server.
dataSocket.send(buildPacket(rconCommand));
if (returnsData) {
// Create a new buffer to receive any response from the rcon command
byte[] buffer = new byte[4000];
// Create the new datagram packet to house the returned results of the command
dataPacketIn = new DatagramPacket(buffer,buffer.length);
// Receive the buffer using the datagram socket.
dataSocket.receive(dataPacketIn);
retStr = new String(dataPacketIn.getData(), 0, dataPacketIn.getLength());
}
else
{
retStr = new String("Command sent on source port: " + dataSocket.getLocalPort());
}
sleeper();
}
catch(IOException ex){
retStr = new String(ex.getMessage());
}
// Return the results
return retStr;
}
}
Here are the arguments to pass in during initialization:
ip = The Ip address of your CoD server
port = The port on which your server recieves Rcon commands
password = Your Rcon password
returnsData = This is a bit flag to tell the send command whether or not to open a receiving buffer fora return response. Of the basic commands, status is probably the only one that needs it so no need for the overhead that comes along with it where other commands are concerned.
receiveTimeout = This is how long to wait for a response (in milliseconds)
sleepTimer = This is how long to pause between sending more commands (in milliseconds). If you find that you are able to send a command fine, but when you try to send two back to back and only the second runs, try increasing this value to add time between the commands.
Once you have successfully initialized NetRcon, you simply use the send() method to send your commands to the server. If the command expects results, they will be returned by this method.