remoteaccessserver.java

来自「这是整套横扫千军3D版游戏的源码」· Java 代码 · 共 279 行

JAVA
279
字号
/*
 * Created on 2006.11.17
 *
 * Protocol description:
 * 
 * - communication is meant to be short - 1 or 2 commands and then connection should be terminated
 * - connection gets closed automatically after 30 seconds of inactivity.
 * - communication is strictly synchronous - when client sends a command server responds with another command.
 *   If same client must query multiple commands, he should either wait for a response after each command
 *   before sending new command, or use new connection for next command.
 * 
 * *** COMMAND LIST: ***
 * 
 * * IDENTIFY key
 *   This is the first command that client should send immediately after connecting. 'key' parameter
 *   is a key provided to the user with which he identifies himself to the server. Server will reply
 *   with either PROCEED or FAILED command.
 *   
 * * PROCEED
 *   Sent by server upon accepting connection.
 *   
 * * FAILED
 *   Sent by server if IDENTIFY command failed (either because of incorrect key or because service is unavailable).
 *
 * * TESTLOGIN username password
 *   Sent by client when trying to figure out if login info is correct. Server will respond with either LOGINOK or LOGINBAD command.
 *
 * * LOGINOK
 *   Sent by server as a response to a successful TESTLOGIN command.
 *   
 * * LOGINBAD
 *   Sent by server as a response to a failed TESTLOGIN command.
 *   
 * * GETACCESS username
 *   Sent by client trying to figure out access status of some user.
 *   Returns 1 for "normal", 2 for "moderator", 3 for "admin".
 *   If user is not found, returns 0 as a result.
 *   If the operation fails for some reason, socket will simply get disconnected.
 *   
 * * QUERYSERVER {server command}  
 *   This will forward the given command directly to server and then forward server's response back to the client.
 *   This command means potential security risc. Will be replaced in the future by a set of user specific commands.
 *   Currently commands that may be passed to this function are limited - only some command are allowed. This is so
 *   in order to avoid some security risks with the command.
 *   If the operation fails for some reason, socket will simply get disconnected.   
 */

import java.io.*;
import java.net.*;
import java.util.*;

public class RemoteAccessServer extends Thread {
	
	final static int TIMEOUT = 30000; // in milliseconds
	final static boolean DEBUG = true;  
	
	public static Vector remoteAccounts = new Vector(); // contains String-s of keys for remote server access
	
	// used with QUERYSERVER command
	public static final String allowedQueryCommands[] = {
		"GETREGISTRATIONDATE",
		"GETINGAMETIME",
		"GETLASTIP",
		"GETLASTLOGINTIME",
		"RELOADUPDATEPROPERTIES",
		"GETLOBBYVERSION",
		"UPDATEMOTD",
		};
	
	public Vector threads = new Vector(); // here we keep a list of all currently running client threads
	private int port;
	
	public RemoteAccessServer(int port) {
		this.port = port;
	}
	
	public void run() {
		try {
	        ServerSocket ss = new ServerSocket(port);

	        while (true) {
	            Socket cs = ss.accept();
	            RemoteClientThread thread = new RemoteClientThread(this, cs);
	        	threads.add(thread);
	        	thread.start();
	        }
		} catch (IOException e) {
			Log.error("Error occured in RemoteAccessServer: " + e.getMessage());
		}
	}
	
}

class RemoteClientThread extends Thread {
    static final int BUF_SIZE = 2048;

    static final byte[] EOL = {(byte)'\r', (byte)'\n' };

    /* unique ID which we will use as a message ID when sending commands to TASServer */
    public int ID = (int)((Math.random() * 65535));
    
    /* reply queue which gets filled by ChanServ automatically */
    Queue replyQueue = new Queue();    
    
    /* socket for the client which we are handling */
    private Socket socket;
    private String IP;
    private boolean identified = false; // if remote client has already identified

    private PrintWriter out;
    private BufferedReader in;
    
    private RemoteAccessServer parent; // so we will know which object spawned this thread
    
    
    RemoteClientThread(RemoteAccessServer parent, Socket s) {
    	this.socket = s;
    	this.parent = parent;
        try {
            socket.setSoTimeout(RemoteAccessServer.TIMEOUT);
            socket.setTcpNoDelay(true);
        } catch (SocketException e) {
        	Log.error("Serious error in RemoteClient constructor (SocketException): " + e.getMessage());
        }
        IP = socket.getInetAddress().getHostAddress();
        
	    try {
	    	out = new PrintWriter(socket.getOutputStream(), true);
	    	in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
	    } catch (IOException e) {
	    	Log.error("Serious error: cannot associate input/output with client socket! Program will now exit ...");
    	    System.exit(1);
    	}
    }
    
	public String readLine() throws IOException {
		return in.readLine();
	}
	
	public void sendLine(String text) {
		if (RemoteAccessServer.DEBUG) System.out.println("RAS: \"" + text + "\"");
		out.println(text);
	}    
    
	private void disconnect() {
		try {
			if (!socket.isClosed()) {
	    	    out.close();
	    	    in.close();
	    	    socket.close();
			}
		} catch (IOException e) {
			// ignore it
		}
	}
	
	private void kill() {
		disconnect();
		parent.threads.remove(this);
	}
    
    public void run() {
   	    String input;
   	    
		try
		{
			while (true) {
				input = readLine();
				if (input == null) throw new IOException();
				if (RemoteAccessServer.DEBUG) System.out.println(IP + ": \"" + input + "\"");
				processCommand(input);
			}
		}
		catch (InterruptedIOException e)
		{
			kill();
			return;
		}    	    
		catch (IOException e)
		{
			kill();
			return;
		}    	   
    }
    
    private void queryTASServer(String command) {
    	ChanServ.sendLine("#" + ID + " " + command);
    	
    }
    private String waitForReply() {
    	return (String)replyQueue.pull(); // will wait until queue doesn't contain a response
    }
    
    public void processCommand(String command) {
    	command = command.trim();
    	if (command.equals("")) return ;
    	
		String[] params = command.split(" ");
		params[0] = params[0].toUpperCase();
		
		if (params[0].equals("IDENTIFY")) {
			if (params.length != 2) return ; // malformed command
			if (!ChanServ.isConnected()) {
				sendLine("FAILED");
				return ;
			}
			for (int i = 0; i < RemoteAccessServer.remoteAccounts.size(); i++)
				if (((String)RemoteAccessServer.remoteAccounts.get(i)).equals(params[1])) {
					sendLine("PROCEED");
					identified = true; // client has successfully identified
					return ;
				}
			sendLine("FAILED");
		} else if (params[0].equals("TESTLOGIN")) {
			if (!identified) return ;
			if (params.length != 3) return ; // malformed command
			if (!ChanServ.isConnected()) {
				sendLine("LOGINBAD");
				return ;
			}
			queryTASServer("TESTLOGIN " + params[1] + " " + params[2]);
			String reply = waitForReply().toUpperCase();
			if (reply.equals("TESTLOGINACCEPT")) {
				sendLine("LOGINOK");
			}
			else
				sendLine("LOGINBAD");
		} else if (params[0].equals("GETACCESS")) {
			if (!identified) return ;
			if (params.length != 2) return ; // malformed command
			if (!ChanServ.isConnected()) {
				kill();
				return ;
			}
			queryTASServer("GETACCOUNTACCESS " + params[1]);
			String reply = waitForReply();

			// if user not found:
			if (reply.equals("User <" + params[1] + "> not found!")) {
				sendLine("0");
				return ;
			}
			
			String[] tmp = reply.split(" ");
			int access = 0;
			try {
				access = Integer.parseInt(tmp[tmp.length-1]);
			} catch (NumberFormatException e) { // should not happen
				kill();
				return ; 
			}
			sendLine("" + (access & 0x7));
		} else if (params[0].equals("QUERYSERVER")) {
			if (!identified) return ;
			if (params.length < 2) return ; // malformed command
			if (!ChanServ.isConnected()) {
				kill();
				return ;
			}
			boolean allow = false;
			for (int i = 0; i < RemoteAccessServer.allowedQueryCommands.length; i++) {
				if (RemoteAccessServer.allowedQueryCommands[i].equals(params[1])) {
					allow = true;
					break;
				}
			}
			
			if (!allow) kill(); // client is trying to execute a command that is not allowed!
			
			queryTASServer(Misc.makeSentence(params, 1));
			String reply = waitForReply();
			sendLine(reply);
		} else {
			// unknown command!
		}
    }
    
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?