Move session init management to new class

This commit is contained in:
P0nk
2021-06-28 12:00:09 +02:00
parent 69a4dd8c6d
commit 5bc2f47883
3 changed files with 121 additions and 75 deletions

View File

@@ -0,0 +1,20 @@
package net.server.coordinator.session;
import net.server.coordinator.session.MapleSessionCoordinator.AntiMulticlientResult;
enum InitializationResult {
SUCCESS(AntiMulticlientResult.SUCCESS),
ALREADY_INITIALIZED(AntiMulticlientResult.REMOTE_PROCESSING),
TIMED_OUT(AntiMulticlientResult.COORDINATOR_ERROR),
ERROR(AntiMulticlientResult.COORDINATOR_ERROR);
private final AntiMulticlientResult antiMulticlientResult;
InitializationResult(AntiMulticlientResult antiMulticlientResult) {
this.antiMulticlientResult = antiMulticlientResult;
}
public AntiMulticlientResult getAntiMulticlientResult() {
return antiMulticlientResult;
}
}

View File

@@ -23,8 +23,6 @@ import client.MapleCharacter;
import client.MapleClient;
import config.YamlConfig;
import net.server.Server;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import net.server.coordinator.login.LoginStorage;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
@@ -38,8 +36,6 @@ import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
/**
@@ -63,7 +59,8 @@ public class MapleSessionCoordinator {
MANY_ACCOUNT_ATTEMPTS,
COORDINATOR_ERROR
}
private final SessionInitialization sessionInit = new SessionInitialization();
private final LoginStorage loginStorage = new LoginStorage();
private final Map<Integer, MapleClient> onlineClients = new HashMap<>();
private final Set<String> onlineRemoteHwids = new HashSet<>();
@@ -72,12 +69,8 @@ public class MapleSessionCoordinator {
private final ConcurrentHashMap<String, String> cachedHostHwids = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Long> cachedHostTimeout = new ConcurrentHashMap<>();
private final List<ReentrantLock> poolLock = new ArrayList<>(100);
private MapleSessionCoordinator() {
for(int i = 0; i < 100; i++) {
poolLock.add(MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER_LOGIN_COORD));
}
}
private static boolean attemptAccountAccess(int accountId, String nibbleHwid, boolean routineCheck) {
@@ -109,10 +102,6 @@ public class MapleSessionCoordinator {
return false;
}
private Lock getCoodinatorLock(String remoteHost) {
return poolLock.get(Math.abs(remoteHost.hashCode()) % 100);
}
public static String getSessionRemoteAddress(IoSession session) {
return (String) session.getAttribute(MapleClient.CLIENT_REMOTE_ADDRESS);
@@ -152,9 +141,8 @@ public class MapleSessionCoordinator {
}
String remoteHost = getSessionRemoteHost(session);
Lock lock = getCoodinatorLock(remoteHost);
AntiMulticlientResult result = addToRemoteHostPoolWithRetries(lock, remoteHost);
switch (result) {
final InitializationResult initResult = sessionInit.initialize(remoteHost);
switch (initResult.getAntiMulticlientResult()) {
case REMOTE_PROCESSING -> {
return false;
}
@@ -181,12 +169,7 @@ public class MapleSessionCoordinator {
return true;
} finally {
lock.lock();
try {
pooledRemoteHosts.remove(remoteHost);
} finally {
lock.unlock();
}
sessionInit.finalize(remoteHost);
}
}
@@ -224,10 +207,9 @@ public class MapleSessionCoordinator {
}
String remoteHost = getSessionRemoteHost(session);
final Lock lock = getCoodinatorLock(remoteHost);
AntiMulticlientResult hostPoolAdditionResult = addToRemoteHostPoolWithRetries(lock, remoteHost);
if (hostPoolAdditionResult != AntiMulticlientResult.SUCCESS) {
return hostPoolAdditionResult;
InitializationResult initResult = sessionInit.initialize(remoteHost);
if (initResult != InitializationResult.SUCCESS) {
return initResult.getAntiMulticlientResult();
}
try {
@@ -254,12 +236,7 @@ public class MapleSessionCoordinator {
return AntiMulticlientResult.SUCCESS;
} finally {
lock.lock();
try {
pooledRemoteHosts.remove(remoteHost);
} finally {
lock.unlock();
}
sessionInit.finalize(remoteHost);
}
}
@@ -271,10 +248,9 @@ public class MapleSessionCoordinator {
return AntiMulticlientResult.SUCCESS;
}
final Lock lock = getCoodinatorLock(remoteHost);
AntiMulticlientResult hostPoolAdditionResult = addToRemoteHostPoolWithRetries(lock, remoteHost);
if (hostPoolAdditionResult != AntiMulticlientResult.SUCCESS) {
return hostPoolAdditionResult;
final InitializationResult initResult = sessionInit.initialize(remoteHost);
if (initResult != InitializationResult.SUCCESS) {
return initResult.getAntiMulticlientResult();
}
try {
@@ -303,48 +279,10 @@ public class MapleSessionCoordinator {
return AntiMulticlientResult.SUCCESS;
} finally {
lock.lock();
try {
pooledRemoteHosts.remove(remoteHost);
} finally {
lock.unlock();
}
sessionInit.finalize(remoteHost);
}
}
private AntiMulticlientResult addToRemoteHostPoolWithRetries(Lock lock, String remoteHost) {
try {
int tries = 0;
while (true) {
if (lock.tryLock()) {
try {
if (pooledRemoteHosts.contains(remoteHost)) {
return AntiMulticlientResult.REMOTE_PROCESSING;
}
pooledRemoteHosts.add(remoteHost);
} finally {
lock.unlock();
}
break;
} else {
if(tries == 2) {
return AntiMulticlientResult.COORDINATOR_ERROR;
}
tries++;
Thread.sleep(1777);
}
}
} catch (Exception e) {
e.printStackTrace();
return AntiMulticlientResult.COORDINATOR_ERROR;
}
return AntiMulticlientResult.SUCCESS;
}
private static void associateHwidAccountIfAbsent(String remoteHwid, int accountId) {
try (Connection con = DatabaseConnection.getConnection()) {
List<String> hwids = SessionDAO.getHwidsForAccount(con, accountId);

View File

@@ -0,0 +1,88 @@
package net.server.coordinator.session;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
/**
* Manages session initialization using remote host (ip address).
*/
public class SessionInitialization {
private final static Logger log = LoggerFactory.getLogger(SessionInitialization.class);
private static final int MAX_INIT_TRIES = 2;
private static final long RETRY_DELAY_MILLIS = 1777;
private final Set<String> remoteHostsInInitState = new HashSet<>();
private final List<Lock> locks = new ArrayList<>(100);
SessionInitialization() {
for (int i = 0; i < 100; i++) {
locks.add(MonitoredReentrantLockFactory.createLock(MonitoredLockType.SERVER_LOGIN_COORD));
}
}
private Lock getLock(String remoteHost) {
return locks.get(Math.abs(remoteHost.hashCode()) % 100);
}
/**
* Try to initialize a session. Should be called <em>before</em> any session initialization procedure.
*
* @return InitializationResult.SUCCESS if initialization was successful.
* If it was successful, finalize() needs to be called shortly after,
* or else the initialization will be left hanging in a bad state,
* which means any subsequent initialization from the same remote host will fail.
*/
public InitializationResult initialize(String remoteHost) {
final Lock lock = getLock(remoteHost);
try {
int tries = 0;
while (true) {
if (lock.tryLock()) {
try {
if (remoteHostsInInitState.contains(remoteHost)) {
return InitializationResult.ALREADY_INITIALIZED;
}
remoteHostsInInitState.add(remoteHost);
} finally {
lock.unlock();
}
break;
} else {
if (tries++ == MAX_INIT_TRIES) {
return InitializationResult.TIMED_OUT;
}
Thread.sleep(RETRY_DELAY_MILLIS);
}
}
} catch (Exception e) {
log.error("Failed to initialize session.", e);
return InitializationResult.ERROR;
}
return InitializationResult.SUCCESS;
}
/**
* Finalize an initialization. Should be called <em>after</em> any session initialization procedure.
*/
public void finalize(String remoteHost) {
final Lock lock = getLock(remoteHost);
lock.lock();
try {
remoteHostsInInitState.remove(remoteHost);
} finally {
lock.unlock();
}
}
}