Coverage Report - net.sourceforge.rconed.BF2Rcon
 
Classes in this File Line Coverage Branch Coverage Complexity
BF2Rcon
0 %
0/74
0 %
0/28
6
 
 1  
 package net.sourceforge.rconed;
 2  
 
 3  
 import java.io.BufferedReader;
 4  
 import java.io.IOException;
 5  
 import java.io.InputStream;
 6  
 import java.io.InputStreamReader;
 7  
 import java.io.OutputStream;
 8  
 import java.net.InetAddress;
 9  
 import java.net.InetSocketAddress;
 10  
 import java.net.Socket;
 11  
 import java.net.SocketTimeoutException;
 12  
 import java.net.UnknownHostException;
 13  
 import java.security.MessageDigest;
 14  
 import java.security.NoSuchAlgorithmException;
 15  
 
 16  
 import net.sourceforge.rconed.exception.BadRcon;
 17  
 import net.sourceforge.rconed.exception.ResponseEmpty;
 18  
 
 19  
 /**
 20  
  * BF2Rcon is a simple Java library for issuing RCON commands to BF2 game servers.
 21  
  * <p/>
 22  
  * This has been used with default and BF2CC managed servers.
 23  
  * <p/>
 24  
  * Example:
 25  
  * <p/>
 26  
  * String response = BF2Rcon.send("127.0.0.1", 6711, "admin", "game.sayAll \"ploppers\"");
 27  
  * <p/>
 28  
  * @author DeadEd
 29  
  */
 30  0
 public class BF2Rcon {
 31  
 
 32  
     final static int RESPONSE_TIMEOUT = 2000;
 33  
 
 34  0
     static Socket rconSocket = null;
 35  0
     static InputStream in = null;
 36  0
     static OutputStream out = null;
 37  
 
 38  
 
 39  
     /**
 40  
      * Send the RCON command to the game server
 41  
      *
 42  
      * @param ipStr     The IP (as a String) of the machine where the RCON command will go.
 43  
      * @param port      The port of the machine where the RCON command will go.
 44  
      * @param password  The RCON password.
 45  
      * @param command   The RCON command (without the rcon prefix).
 46  
      * @return The reponse text from the server after trying the RCON command.
 47  
      * @throws SocketTimeoutException when there is any problem communicating with the server.
 48  
      * @throws BadRcon when authentication fails
 49  
      * @throws ResponseEmpty when the response is empty
 50  
      */
 51  
     public static String send(String ipStr, int port, String password, String command) throws SocketTimeoutException, BadRcon, ResponseEmpty {
 52  0
         return send(ipStr, port, password, command, 0);
 53  
     }
 54  
     
 55  
     /**
 56  
      * Send the RCON command to the game server (must have been previously authed with the correct rcon_password)
 57  
      *
 58  
      * @param ipStr     The IP (as a String) of the machine where the RCON command will go.
 59  
      * @param port      The port of the machine where the RCON command will go.
 60  
      * @param password  The RCON password.
 61  
      * @param command   The RCON command (without the rcon prefix).
 62  
      * @param localPort The port of the local machine to use for sending out the RCON request.
 63  
      * @return The reponse text from the server after trying the RCON command.
 64  
      * @throws SocketTimeoutException when there is any problem communicating with the server.
 65  
      * @throws BadRcon when authentication fails
 66  
      * @throws ResponseEmpty when the response is empty
 67  
      */
 68  
     public static String send(String ipStr, int port, String password, String command, int localPort) throws SocketTimeoutException, BadRcon, ResponseEmpty {
 69  0
         return send(ipStr, port, password, command, null, localPort);
 70  
     }
 71  
     
 72  
     /**
 73  
      * Send the RCON command to the game server (must have been previously authed with the correct rcon_password)
 74  
      *
 75  
      * @param ipStr     The IP (as a String) of the machine where the RCON command will go.
 76  
      * @param port      The port of the machine where the RCON command will go.
 77  
      * @param password  The RCON password.
 78  
      * @param command   The RCON command (without the rcon prefix).
 79  
      * @param localhost The IP of the local machine to use for sending out the RCON request.
 80  
      * @param localPort The port of the local machine to use for sending out the RCON request.
 81  
      * @return The reponse text from the server after trying the RCON command.
 82  
      * @throws SocketTimeoutException when there is any problem communicating with the server.
 83  
      * @throws BadRcon when authentication fails
 84  
      * @throws ResponseEmpty when the response is empty
 85  
      */
 86  
     public static String send(String ipStr, int port, String password, String command, InetAddress localhost, int localPort) throws SocketTimeoutException, BadRcon, ResponseEmpty {
 87  0
         StringBuffer response = new StringBuffer();
 88  
 
 89  
         try {
 90  0
             rconSocket = new Socket();
 91  
 
 92  
             //InetAddress addr = InetAddress.getLocalHost();
 93  
             //byte[] ipAddr = addr.getAddress();
 94  
             //InetAddress inetLocal = InetAddress.getByAddress(ipAddr);
 95  
             
 96  
             //rconSocket.bind(new InetSocketAddress(inetLocal, localPort));
 97  0
             rconSocket.bind(new InetSocketAddress(localhost, localPort));
 98  0
             rconSocket.connect(new InetSocketAddress(ipStr, port), RESPONSE_TIMEOUT);
 99  
 
 100  0
             out = rconSocket.getOutputStream();
 101  0
             in = rconSocket.getInputStream();
 102  0
             BufferedReader buffRead = new BufferedReader(new InputStreamReader(in));
 103  
 
 104  0
             rconSocket.setSoTimeout(RESPONSE_TIMEOUT);
 105  
 
 106  0
             String digestSeed = "";
 107  0
             boolean loggedIn = false;
 108  0
             boolean keepGoing = true;
 109  0
             while(keepGoing) {
 110  0
                 String receivedContent = buffRead.readLine();
 111  0
                 if(receivedContent.startsWith("### Digest seed: ")) {
 112  0
                     digestSeed = receivedContent.substring(17, receivedContent.length());
 113  
                     try {
 114  0
                         MessageDigest md5 = MessageDigest.getInstance("MD5");
 115  0
                         md5.update(digestSeed.getBytes());
 116  0
                         md5.update(password.getBytes());
 117  0
                         String digestStr = "login "+ digestedToHex(md5.digest()) +"\n";
 118  0
                         out.write(digestStr.getBytes());
 119  0
                     } catch (NoSuchAlgorithmException e1) {
 120  0
                         response.append("MD5 algorithm not available - unable to complete RCON request.");
 121  0
                         keepGoing = false;
 122  0
                     }
 123  0
                 } else if(receivedContent.startsWith("error: not authenticated: you can only invoke 'login'")) {
 124  0
                     throw new BadRcon();
 125  0
                 } else if(receivedContent.startsWith("Authentication failed.")) {
 126  0
                     throw new BadRcon();
 127  0
                 } else if(receivedContent.startsWith("Authentication successful, rcon ready.")) {
 128  0
                     keepGoing = false;
 129  0
                     loggedIn = true;
 130  
                 }
 131  0
             }
 132  0
             if(loggedIn) {
 133  
                 // logged in, now we can execute the command
 134  0
                 String cmd = "\u0002exec "+ command +"\n";
 135  0
                 out.write(cmd.getBytes());
 136  
 
 137  0
                 readResponse(buffRead, response);
 138  0
                 if(response.length() == 0) {
 139  0
                     throw new ResponseEmpty();
 140  
                 }
 141  
             }
 142  
 
 143  0
         } catch (SocketTimeoutException timeout) {
 144  0
             throw timeout;
 145  0
         } catch (UnknownHostException e) {
 146  0
             response.append("UnknownHostException: "+ e.getMessage());
 147  0
         } catch (IOException e) {
 148  0
             response.append("Couldn't get I/O for the connection: "+ e.getMessage());
 149  0
             e.printStackTrace();
 150  
         } finally {
 151  0
             try {
 152  0
                 if(out != null) {
 153  0
                     out.close();
 154  
                 }
 155  0
                 if(in != null) {
 156  0
                     in.close();
 157  
                 }
 158  0
                 if(rconSocket != null) {
 159  0
                     rconSocket.close();
 160  
                 }
 161  0
             } catch (IOException e1) {
 162  
                 // eat ... messed up at this point anyway 
 163  0
             } 
 164  0
         }
 165  
 
 166  0
         return response.toString();
 167  
     }
 168  
 
 169  
     /**
 170  
      * @param buffRead where to read from
 171  
      * @param sb where to put read data
 172  
      * @throws IOException
 173  
      */
 174  
     private static void readResponse(BufferedReader buffRead, StringBuffer sb) throws IOException {
 175  
         int ch;
 176  
         while(true) {
 177  0
             ch = buffRead.read();
 178  0
             if(ch == -1 || ch == 4) {
 179  0
                 return;
 180  
             }
 181  0
             sb.append((char)ch);
 182  
         }
 183  
     }
 184  
 
 185  
     private static String digestedToHex(byte digest[]) {
 186  0
         StringBuffer store = new StringBuffer();
 187  0
         for(int x=0; x < digest.length; x++) {
 188  0
             byte bite = digest[x];
 189  0
             String val = Integer.toHexString(bite & 255);
 190  0
             if(val.length() == 1) {
 191  0
                 store.append("0");
 192  
             }
 193  0
             store.append(val);
 194  
         }
 195  0
         return store.toString();
 196  
     }
 197  
 }