Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package server.login;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.ServerSocketChannel;
- import java.nio.channels.SocketChannel;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.TimeUnit;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import server.net.Cryption;
- import server.net.Stream;
- import server.world.World;
- /**
- * Handles waiting logins
- * @author Colby
- */
- public class LoginHandler {
- private static final Logger log = Logger.getLogger(LoginHandler.class.toString());
- public LoginHandler(World world) {
- this.world = world;
- sessions = new ArrayList<LoginSession>(128);
- }
- private final List<LoginSession> sessions;
- public final World world;
- public void register(SocketChannel schan) {
- try {
- sessions.add(new LoginSession(schan));
- } catch (IOException e) {
- log.throwing(null, null, e);
- }
- }
- public void startLogins() {
- log.info("Starting login handler...");
- world.logicService.schedule(createHandlerTask(), 100L, TimeUnit.MILLISECONDS);
- }
- public void startServerSock(InetAddress bind, int port) {
- log.log(Level.INFO, "Starting game socket on {0}:{1}", new Object[]{bind, port});
- world.workService.execute(createSocketTask(bind, port));
- }
- private Runnable createSocketTask(final InetAddress bind, final int port) {
- return new Runnable() {
- public void run() {
- try {
- ServerSocketChannel listener = null;
- try {
- listener = ServerSocketChannel.open();
- listener.socket().bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), port));
- do {
- try {
- SocketChannel schan = listener.accept();
- LoginHandler.this.register(schan);
- log.log(Level.INFO, "New connection: {0}", schan.socket().getInetAddress().getHostAddress());
- } catch (IOException e) {
- log.throwing(null, null, e);
- }
- } while (true);
- } finally {
- if (listener != null) {
- listener.close();
- }
- }
- } catch (IOException e) {
- log.throwing(null, null, e);
- }
- }
- };
- }
- private Runnable createHandlerTask() {
- return new Runnable() {
- public void run() {
- for (LoginSession session : sessions) {
- try {
- if (!session.process()) {
- sessions.remove(session);
- if (!session.valid) {
- session.schan.close();
- } else {
- log.log(Level.INFO, "New player: {0}", session.toString());
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- };
- }
- public static class LoginSession {
- public LoginSession(SocketChannel schan) throws IOException {
- if (schan.isBlocking()) {
- schan.configureBlocking(false);
- }
- schan.socket().setTcpNoDelay(true);
- schan.socket().setSoTimeout(10000);
- this.schan = schan;
- inBuffer = ByteBuffer.allocate(128);
- outBuffer = ByteBuffer.allocate(128);
- inStream = new Stream(inBuffer.array());
- outStream = new Stream(outBuffer.array());
- serverSessionKey = ((long) (Math.random() * 99999999D) << 32) + (long) (Math.random() * 99999999D);
- }
- private Stage stage = Stage.First;
- private Stream inStream, outStream;
- private ByteBuffer inBuffer, outBuffer;
- private SocketChannel schan;
- private long serverSessionKey;
- private int loginPacketSize, loginEncryptPacketSize;
- public boolean valid;
- public static enum Stage {
- First(2),
- Second(2),
- Third(-1),
- Done(-1);
- Stage(int len) {
- this.len = len;
- }
- public final int len;
- }
- @Override
- public String toString() {
- return schan.socket().getInetAddress().getHostAddress();
- }
- public boolean process() throws IOException {
- inBuffer.flip();
- schan.read(inBuffer);
- inBuffer.flip();
- if (inBuffer.remaining() < ((stage == Stage.Third) ? loginPacketSize : stage.len)) {
- return true;
- }
- inStream.currentOffset = inBuffer.position();
- outStream.currentOffset = outBuffer.position();
- switch (stage) {
- case First:
- int lType = inStream.readUnsignedByte();
- if (lType != 14) {
- error("Unexpected login type: " + lType);
- return false;
- }
- int nameHash = inStream.readUnsignedByte();
- //Prevent timeout
- for (int i = 0; i < 8; i++) {
- outStream.writeByte(0);
- }
- // 0=crypt, 2=skip
- outStream.writeByte(0);
- outStream.writeQWord(serverSessionKey);
- stage = Stage.Second;
- break;
- case Second:
- //16=new, 18=reconnect
- int loginType = inStream.readUnsignedByte();
- if (loginType != 16 && loginType != 18) {
- error("Unexpected login type " + loginType);
- return false;
- }
- loginPacketSize = inStream.readUnsignedByte();
- // the size of the RSA encrypted part (containing password)
- loginEncryptPacketSize = loginPacketSize - (36 + 1 + 1 + 2);
- if (loginEncryptPacketSize <= 0) {
- error("Zero RSA packet size!");
- return false;
- }
- stage = Stage.Third;
- break;
- case Third:
- int i1 = inStream.readUnsignedByte();
- int i0 = inStream.readUnsignedWord();
- if (i1 != 255 || i0 != 317) {
- error("Wrong login packet magic ID (expected 255, 317): " + i1 + ":" + i0);
- return false;
- }
- int lowMemoryVersion = inStream.readUnsignedByte();
- for (int i = 0; i < 9; i++) {
- inStream.readDWord();
- }
- // don't count length byte
- loginEncryptPacketSize--;
- int tmp = inStream.readUnsignedByte();
- if (loginEncryptPacketSize != tmp) {
- error("Encrypted packet data length (" + loginEncryptPacketSize + ") different from length byte thereof (" + tmp + ")");
- return false;
- }
- tmp = inStream.readUnsignedByte();
- if (tmp != 10) {
- error("Encrypted packet Id was " + tmp + " but expected 10");
- return false;
- }
- long clientSessionKey = inStream.readQWord();
- serverSessionKey = inStream.readQWord();
- int uid = inStream.readDWord();
- String username = inStream.readString().replaceAll(" ", "_").toLowerCase();
- String password = inStream.readString().replaceAll(" ", "_").toLowerCase();
- int sessionKey[] = new int[4];
- sessionKey[0] = (int) (clientSessionKey >> 32);
- sessionKey[1] = (int) clientSessionKey;
- sessionKey[2] = (int) (serverSessionKey >> 32);
- sessionKey[3] = (int) serverSessionKey;
- inStream.packetEncryption = new Cryption(sessionKey);
- for (int i = 0; i < 4; i++) {
- sessionKey[i] += 50;
- }
- outStream.packetEncryption = new Cryption(sessionKey);
- outStream.writeByte(2);
- outStream.writeByte(2);
- outStream.writeByte(0);
- valid = true;
- break;
- }
- outBuffer.position(outStream.currentOffset);
- outBuffer.flip();
- schan.write(outBuffer);
- if (outBuffer.remaining() == 0) {
- return false;
- }
- outBuffer.flip();
- return true;
- }
- private void error(String msg) {
- log.log(Level.WARNING, "[{0}]:{1}", new Object[]{schan.socket().getInetAddress().getHostAddress(), msg});
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement