001package net.minecraft.network.rcon;
002
003import java.io.BufferedInputStream;
004import java.io.ByteArrayOutputStream;
005import java.io.DataOutputStream;
006import java.io.IOException;
007import java.net.Socket;
008import java.net.SocketTimeoutException;
009
010public class RConThreadClient extends RConThreadBase
011{
012    /**
013     * True if the client has succefssfully logged into the RCon, otherwise false
014     */
015    private boolean loggedIn = false;
016
017    /** The client's Socket connection */
018    private Socket clientSocket;
019
020    /** A buffer for incoming Socket data */
021    private byte[] buffer = new byte[1460];
022
023    /** The RCon password */
024    private String rconPassword;
025
026    RConThreadClient(IServer par1IServer, Socket par2Socket)
027    {
028        super(par1IServer);
029        this.clientSocket = par2Socket;
030
031        try
032        {
033            this.clientSocket.setSoTimeout(0);
034        }
035        catch (Exception var4)
036        {
037            this.running = false;
038        }
039
040        this.rconPassword = par1IServer.getStringProperty("rcon.password", "");
041        this.logInfo("Rcon connection from: " + par2Socket.getInetAddress());
042    }
043
044    public void run()
045    {
046        try
047        {
048            while (true)
049            {
050                if (!this.running)
051                {
052                    break;
053                }
054
055                BufferedInputStream bufferedinputstream = new BufferedInputStream(this.clientSocket.getInputStream());
056                int i = bufferedinputstream.read(this.buffer, 0, 1460);
057
058                if (10 <= i)
059                {
060                    byte b0 = 0;
061                    int j = RConUtils.getBytesAsLEInt(this.buffer, 0, i);
062
063                    if (j != i - 4)
064                    {
065                        return;
066                    }
067
068                    int k = b0 + 4;
069                    int l = RConUtils.getBytesAsLEInt(this.buffer, k, i);
070                    k += 4;
071                    int i1 = RConUtils.getRemainingBytesAsLEInt(this.buffer, k);
072                    k += 4;
073
074                    switch (i1)
075                    {
076                        case 2:
077                            if (this.loggedIn)
078                            {
079                                String s = RConUtils.getBytesAsString(this.buffer, k, i);
080
081                                try
082                                {
083                                    this.sendMultipacketResponse(l, this.server.executeCommand(s));
084                                }
085                                catch (Exception exception)
086                                {
087                                    this.sendMultipacketResponse(l, "Error executing: " + s + " (" + exception.getMessage() + ")");
088                                }
089
090                                continue;
091                            }
092
093                            this.sendLoginFailedResponse();
094                            continue;
095                        case 3:
096                            String s1 = RConUtils.getBytesAsString(this.buffer, k, i);
097                            int j1 = k + s1.length();
098
099                            if (0 != s1.length() && s1.equals(this.rconPassword))
100                            {
101                                this.loggedIn = true;
102                                this.sendResponse(l, 2, "");
103                                continue;
104                            }
105
106                            this.loggedIn = false;
107                            this.sendLoginFailedResponse();
108                            continue;
109                        default:
110                            this.sendMultipacketResponse(l, String.format("Unknown request %s", new Object[] {Integer.toHexString(i1)}));
111                            continue;
112                    }
113                }
114            }
115        }
116        catch (SocketTimeoutException sockettimeoutexception)
117        {
118        }
119        catch (IOException ioexception)
120        {
121        }
122        catch (Exception exception1)
123        {
124            System.out.println(exception1);
125        }
126        finally
127        {
128            this.closeSocket();
129        }
130    }
131
132    /**
133     * Sends the given response message to the client
134     */
135    private void sendResponse(int par1, int par2, String par3Str) throws IOException
136    {
137        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(1248);
138        DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);
139        dataoutputstream.writeInt(Integer.reverseBytes(par3Str.length() + 10));
140        dataoutputstream.writeInt(Integer.reverseBytes(par1));
141        dataoutputstream.writeInt(Integer.reverseBytes(par2));
142        dataoutputstream.writeBytes(par3Str);
143        dataoutputstream.write(0);
144        dataoutputstream.write(0);
145        this.clientSocket.getOutputStream().write(bytearrayoutputstream.toByteArray());
146    }
147
148    /**
149     * Sends the standard RCon 'authorization failed' response packet
150     */
151    private void sendLoginFailedResponse() throws IOException
152    {
153        this.sendResponse(-1, 2, "");
154    }
155
156    /**
157     * Splits the response message into individual packets and sends each one
158     */
159    private void sendMultipacketResponse(int par1, String par2Str) throws IOException
160    {
161        int j = par2Str.length();
162
163        do
164        {
165            int k = 4096 <= j ? 4096 : j;
166            this.sendResponse(par1, 0, par2Str.substring(0, k));
167            par2Str = par2Str.substring(k);
168            j = par2Str.length();
169        }
170        while (0 != j);
171    }
172
173    /**
174     * Closes the client socket
175     */
176    private void closeSocket()
177    {
178        if (null != this.clientSocket)
179        {
180            try
181            {
182                this.clientSocket.close();
183            }
184            catch (IOException ioexception)
185            {
186                this.logWarning("IO: " + ioexception.getMessage());
187            }
188
189            this.clientSocket = null;
190        }
191    }
192}