diff --git a/src/net/common/sessionmanager.cpp b/src/net/common/sessionmanager.cpp index 5c68ed8f..097c3e69 100644 --- a/src/net/common/sessionmanager.cpp +++ b/src/net/common/sessionmanager.cpp @@ -34,8 +34,6 @@ #include #include -#include // debug - remove me - using namespace std; #define SERVER_MAX_GUEST_USERS_LOBBY 50 // LG: Maximum number of guests users in lobby allowed diff --git a/tests/src/de/pokerth/test/TestBase.java b/tests/src/de/pokerth/test/TestBase.java index 4e80c327..d5bb3b79 100644 --- a/tests/src/de/pokerth/test/TestBase.java +++ b/tests/src/de/pokerth/test/TestBase.java @@ -389,4 +389,243 @@ public abstract class TestBase { return cipher.doFinal(ciphertext); } + + /** + * Description: + * + * This test runs several guests users in PokerTH Server. + * Starts N threads thats connects to server "at once": There is a delay between each connection, to avoid error 133 + * (NOTE: I didn't succeed avoid this message. So, it's better to disable "ServerBruteForceProtection" in config.xml) + * Once connected, each thread waits until all other connects to simulate N users at once + * + * When all threads are connected, each thread gets unlocked and close connections, in an orderly way. + * + * + * Running: + * + * Tests accepts JVM property options: + * -Dpthserver.type, type of server: 'S' for dedicated, 'O' for official (default) + * -Dpthserver.passwd, password for dedicated server + * -Dpthserver.numthreads, number of threads (guests users) launched (5 default) + * -Dpthserver.waitfor, time all users remain connected until released. + * Format: XXX[m,s,M] for m(milliseconds), s(seconds), M(minutes). Eg: 1M (1 minute), 45s (45 seconds) + * Default: 1s + * + * For DEDICATED_SERVER Server must be faked to accept guest connections (aren't allowed by default). + * + * Purpose: + * + * Final purpose of this test, is check whether a guest connection isn't permitted + * once the maximum number of guests players allowed is reached + * To achieve that, N (NUM_THREADS) must be SERVER_MAX_GUEST_USERS + 1. That value is defined in ServerLobbyThread + * In that case, test will fail, because it's not supposed to receive that error message. + * Test must be corrected: + * - Last thread launched (or the one that makes SERVER_MAX_GUEST_USERS + 1, and next ones), must receive an error + * - To do that, msg.hasErrorMessage() must be true, and reason (msg.getErrorMessage().getErrorReason()) + * must be ERR_NET_SERVER_FULL (error gameIsFull) + * + * + * TODO: + * + * This test must be modified to adapt to: + * - Java8 (much simple threads) Runnable name = () -> {code} + * - Modern concurrency design: using Executors, Barriers and CountDownLatch + * - Test a guarantee exception when limit is reached. + * + * @author albmed + * + * @return + * @throws Exception + */ + public int guestInitThreaded() throws Exception { + + String serverType = System.getProperty("pthserver.type"); + String serverPasswd = System.getProperty("pthserver.passwd"); + String numThreadsStr = System.getProperty("pthserver.numthreads"); + String sleepForStr = System.getProperty("pthserver.waitfor"); + + // if serverType not provided or wrong, suppose official server + if (serverType == null || !serverType.matches("[OoSs]")) { + serverType = "O"; + serverPasswd = ""; + } + + // if dedicated server passwd is mandatory + if (serverType.equalsIgnoreCase("S") && (serverPasswd == null || serverPasswd.trim().length() == 0)) + fail("Server Passwd needed on Dedicated server"); + + // if numThreads not provided supposed 5 (must match with SERVER_MAX_GUEST_USERS) + int numThreads = 5; + if (numThreadsStr != null && numThreadsStr.matches("[0-9]+")) + numThreads = Integer.valueOf(numThreadsStr).intValue(); + + // waits for, at least 1sec, when all threads are alive and waiting + // can wait longer if, a one want to do a test with a real client. + // Format is: time[unit], where unit is "m" (milli), "s" (seconds) or "M" (minutes) + long sleepFor = 1000L; + if (sleepForStr != null && sleepForStr.matches("([0-9]+)([msM]?)")) { + long units = 1L; + if ((sleepForStr.charAt(sleepForStr.length() - 1) + "").matches("[msM]")) { + switch (sleepForStr.charAt(sleepForStr.length() - 1)) { + case 'm': units = 1L; break; // milliseconds + case 's': units = 1000L; break; // seconds + case 'M': units = 60L*1000L; break; // minutes + default: break; + } + sleepForStr = sleepForStr.substring(0, sleepForStr.length() -1); + } + + long tmp = Long.valueOf(sleepForStr).longValue() * units; + if (tmp > sleepFor) sleepFor = tmp; + } + + class ThreadGuest implements Runnable { + Thread t; + Object lock; + String name; + String type; + Socket s; + String passwd; + + public ThreadGuest(String _name, String _type, String _passwd, Object _lock) { + this.name = _name; + if (_lock == null) lock = new Object(); + this.lock = _lock; + this.type = _type; + this.passwd = _passwd; + } + + public Object getLock() { return this.lock; } + public Thread getThread() { return this.t; } + + public void start() { + if (t == null) { + t = new Thread(this); + t.start(); + } + } + + @Override + public void run() { + int playerId = connect(); + + System.out.println("[" + System.currentTimeMillis() + " - " + name + "]: PlayerId: " + playerId + " connected"); + + // Wait to make all guests users connected at once + synchronized (lock) { + try { + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + System.out.println("[" + System.currentTimeMillis() + " - " + name + "]: PlayerId: " + playerId + " released"); + + // Close conn + if (s != null && !s.isClosed()) try {s.close();} catch (IOException e) {} + } + + public int connect() { + Exception excep = null; + int playerId = -1; + + try { + s = new Socket("localhost", 7234); + PokerTHMessage msg = receiveMessage(s); + assertTrue(msg.hasAnnounceMessage()); + + if (type.equalsIgnoreCase("S")) assertTrue(msg.getAnnounceMessage().getServerType() == ServerType.serverTypeInternetNoAuth); + + AnnounceMessage.Version requestedVersion = AnnounceMessage.Version.newBuilder() + .setMajorVersion(PROTOCOL_VERSION_MAJOR) + .setMinorVersion(PROTOCOL_VERSION_MINOR) + .build(); + + InitMessage init; + if (type.equalsIgnoreCase("S")) { + init = InitMessage.newBuilder() + .setBuildId(0) + .setLogin(InitMessage.LoginType.unauthenticatedLogin) + .setRequestedVersion(requestedVersion) + .setNickName(name).setAuthServerPassword(passwd) + .build(); + } + else { + init = InitMessage.newBuilder() + .setBuildId(0) + .setLogin(InitMessage.LoginType.guestLogin) + .setRequestedVersion(requestedVersion) + .setNickName(name) + .build(); + } + + msg = PokerTHMessage.newBuilder() + .setMessageType(PokerTHMessageType.Type_InitMessage) + .setInitMessage(init) + .build(); + + sendMessage(msg, s); + + msg = receiveMessage(s); + failOnErrorMessage(msg); + + if (msg.hasInitAckMessage() && msg.getMessageType() == PokerTHMessageType.Type_InitAckMessage) { + InitAckMessage initAck = msg.getInitAckMessage(); + assertTrue(initAck.getYourPlayerId() != 0L); + assertTrue(!initAck.hasYourAvatarHash()); + playerId = initAck.getYourPlayerId(); + } + else { + failOnErrorMessage(msg); + fail("Invalid message."); + } + + } + catch (Exception e) { + excep = e; + e.printStackTrace(); + } + finally { + if (excep != null) { + if (s != null) try {s.close();} catch (IOException e) {} + } + } + + return playerId; + } + + } + + ThreadGuest[] threads = new ThreadGuest[numThreads]; + + for (int i = 0; i < threads.length; i++) { + threads[i] = new ThreadGuest("Guest" + String.format("%05d",i), serverType, serverPasswd, new Object()); + threads[i].start(); + + // Must wait over a second, before start next thread, to avoid error 133 (ERR_NET_INIT_BLOCKED) + // Don't know why this don't works. I had to disable ServerBruteForceProtection on server config file. + // So, this can be reduced to a few milliseconds (better not to comment or remove). + Thread.sleep(1500L); + } + + // All threads are running and waiting. + Thread.sleep(sleepFor); + + // Unlock, and let threads die. + for (int i = 0; i < threads.length; i++) { + Object lock = threads[i].getLock(); + synchronized (lock) { + lock.notify(); + } + try { + threads[i].getThread().join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + return -1; + } + } diff --git a/tests/src/de/pokerth/test/ThreadedGuestTest.java b/tests/src/de/pokerth/test/ThreadedGuestTest.java deleted file mode 100644 index e3bf2b7b..00000000 --- a/tests/src/de/pokerth/test/ThreadedGuestTest.java +++ /dev/null @@ -1,256 +0,0 @@ -package de.pokerth.test; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.net.Socket; - -import org.junit.Assert; -import org.junit.Test; - -import de.pokerth.protocol.ProtoBuf.AnnounceMessage; -import de.pokerth.protocol.ProtoBuf.AnnounceMessage.ServerType; -import de.pokerth.protocol.ProtoBuf.ErrorMessage; -import de.pokerth.protocol.ProtoBuf.InitAckMessage; -import de.pokerth.protocol.ProtoBuf.InitMessage; -import de.pokerth.protocol.ProtoBuf.PokerTHMessage; -import de.pokerth.protocol.ProtoBuf.PokerTHMessage.PokerTHMessageType; - -/** - * Description: - * - * This test runs several guests users in PokerTH Server. - * Starts N threads thats connects to server "at once": There is a delay between each connection, to avoid error 133 - * (NOTE: I didn't succed avoid this message. So, it's better to disable "ServerBruteForceProtection" in config.xml) - * Once connected, each thread waits until all other connects to simulate N users at once - * - * When all threads are connected, each thread gets unlocked and close connections, in an orderly way. - * - * - * Running: - * - * For OFFICIAL_SERVER, runs with type='O', passwd is ignored - * For DEDICATED_SERVER: - * - Server must be faked to accept guest connections (aren't allowed by default). - * Method ServerLobbyThread::HandleNetPacketInit() must be changed - * - runs this test, with type='S' and passwd for dedicated server - * - * Purpose: - * - * Final purpose of this test, is check whether a guest connection isn't permitted - * once the maximum number of guests players allowed is reached - * To achieve that, N (NUM_THREADS) must be SERVER_MAX_GUEST_USERS + 1. That value is defined in ServerLobbyThread - * In that case, test will fail, because it's not supposed to receive that error message. - * Test must be corrected: - * - Last thread launched (or the one that makes SERVER_MAX_GUEST_USERS + 1, and next ones), must receive an error - * - To do that, msg.hasErrorMessage() must be true, and reason (msg.getErrorMessage().getErrorReason()) - * must be ERR_NET_SERVER_FULL (error gameIsFull) - * - * - * TODO: - * - * This test must be modified to adapt to: - * - Java8 (much simple threads) Runnable name = () -> {code} - * - Modern concurrency design: using Executors, Barriers and CountDownLatch - * - * - * @author albmed - * - */ -public class ThreadedGuestTest { - - public static final String type = "S"; - public static final String passwd = "PasswdServer"; - - public static final int NUM_THREADS = 7; - - @Test - public void threadedGuestTest() throws InterruptedException { - Assert.assertNotNull(type); - if (!type.matches("[OoSs]")) Assert.fail("No valid option"); - - if (type.equalsIgnoreCase("S") && (passwd == null || passwd.trim().length() == 0)) - Assert.fail("Server Passwd needed on Dedicated server"); - - ThreadGuest[] threads = new ThreadGuest[NUM_THREADS]; - - for (int i = 0; i < threads.length; i++) { - threads[i] = new ThreadGuest("Guest" + String.format("%05d",i), type, passwd, new Object()); - threads[i].start(); - - Thread.sleep(1500L); // Must wait over a second, before start next thread, to avoid error 133 (ERR_NET_INIT_BLOCKED) - } - - Thread.sleep(1000L); - - for (int i = 0; i < threads.length; i++) { - Object lock = threads[i].getLock(); - synchronized (lock) { - lock.notify(); - } - try { - threads[i].getThread().join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - } - - public static PokerTHMessage receiveMessage(Socket s) throws Exception { - byte[] header = new byte[4]; - s.getInputStream().read(header); - int size = 0; - for (int i = 0; i < 4; i++) { - size <<= 8; - size |= (int)header[i]; - } - byte[] data = new byte[size]; - s.getInputStream().read(data); - return PokerTHMessage.parseFrom(data); - } - - public static void sendMessage(PokerTHMessage msg, Socket s) throws Exception { - int size = msg.getSerializedSize(); - byte[] header = new byte[4]; - for (int i = 0; i < 4; i++) - { - header[i] = (new Integer(size >>> 24)).byteValue(); - size <<= 8; - } - s.getOutputStream().write(header); - s.getOutputStream().write(msg.toByteArray()); - } - - - public static void failOnErrorMessage(PokerTHMessage msg) { - if (msg.hasErrorMessage()) - { - ErrorMessage error = msg.getErrorMessage(); - fail("Received error: " + error.getErrorReason().toString()); - } - } - -} - -class ThreadGuest implements Runnable { - - public final int PROTOCOL_VERSION_MAJOR = 5; - public final int PROTOCOL_VERSION_MINOR = 1; - - Thread t; - Object lock; - String name; - String type; - Socket s; - String passwd; - - public ThreadGuest(String _name, String _type, String _passwd, Object _lock) { - this.name = _name; - if (_lock == null) lock = new Object(); - this.lock = _lock; - this.type = _type; - this.passwd = _passwd; - } - - public Object getLock() { return this.lock; } - public Thread getThread() { return this.t; } - - public void start() { - if (t == null) { - t = new Thread(this); - t.start(); - } - } - - @Override - public void run() { - int playerId = connect(); - - System.out.println("[" + System.currentTimeMillis() + " - " + name + "]: PlayerId: " + playerId + " connected"); - - // Wait to make all guests users connected at once - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - System.out.println("[" + System.currentTimeMillis() + " - " + name + "]: PlayerId: " + playerId + " released"); - - // Close conn - if (s != null && !s.isClosed()) try {s.close();} catch (IOException e) {} - } - - public int connect() { - Exception excep = null; - int playerId = -1; - - try { - s = new Socket("localhost", 7234); - PokerTHMessage msg = ThreadedGuestTest.receiveMessage(s); - Assert.assertTrue(msg.hasAnnounceMessage()); - - if (type.equalsIgnoreCase("S")) Assert.assertTrue(msg.getAnnounceMessage().getServerType() == ServerType.serverTypeInternetNoAuth); - - AnnounceMessage.Version requestedVersion = AnnounceMessage.Version.newBuilder() - .setMajorVersion(PROTOCOL_VERSION_MAJOR) - .setMinorVersion(PROTOCOL_VERSION_MINOR) - .build(); - - InitMessage init; - if (type.equalsIgnoreCase("S")) { - init = InitMessage.newBuilder() - .setBuildId(0) - .setLogin(InitMessage.LoginType.unauthenticatedLogin) - .setRequestedVersion(requestedVersion) - .setNickName(name).setAuthServerPassword(passwd) - .build(); - } - else { - init = InitMessage.newBuilder() - .setBuildId(0) - .setLogin(InitMessage.LoginType.guestLogin) - .setRequestedVersion(requestedVersion) - .setNickName(name) - .build(); - } - - msg = PokerTHMessage.newBuilder() - .setMessageType(PokerTHMessageType.Type_InitMessage) - .setInitMessage(init) - .build(); - - ThreadedGuestTest.sendMessage(msg, s); - - msg = ThreadedGuestTest.receiveMessage(s); - ThreadedGuestTest.failOnErrorMessage(msg); - - if (msg.hasInitAckMessage() && msg.getMessageType() == PokerTHMessageType.Type_InitAckMessage) { - InitAckMessage initAck = msg.getInitAckMessage(); - assertTrue(initAck.getYourPlayerId() != 0L); - assertTrue(!initAck.hasYourAvatarHash()); - playerId = initAck.getYourPlayerId(); - } - else { - ThreadedGuestTest.failOnErrorMessage(msg); - Assert.fail("Invalid message."); - } - } - catch (Exception e) { - excep = e; - e.printStackTrace(); - } - finally { - if (excep != null) { - if (s != null) try {s.close();} catch (IOException e) {} - } - } - - return playerId; - } - -}