Move session init management to new class
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,8 +23,6 @@ import client.MapleCharacter;
|
|||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
import net.server.audit.locks.MonitoredLockType;
|
|
||||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
|
||||||
import net.server.coordinator.login.LoginStorage;
|
import net.server.coordinator.login.LoginStorage;
|
||||||
import org.apache.mina.core.session.IoSession;
|
import org.apache.mina.core.session.IoSession;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -38,8 +36,6 @@ import java.util.*;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,7 +59,8 @@ public class MapleSessionCoordinator {
|
|||||||
MANY_ACCOUNT_ATTEMPTS,
|
MANY_ACCOUNT_ATTEMPTS,
|
||||||
COORDINATOR_ERROR
|
COORDINATOR_ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final SessionInitialization sessionInit = new SessionInitialization();
|
||||||
private final LoginStorage loginStorage = new LoginStorage();
|
private final LoginStorage loginStorage = new LoginStorage();
|
||||||
private final Map<Integer, MapleClient> onlineClients = new HashMap<>();
|
private final Map<Integer, MapleClient> onlineClients = new HashMap<>();
|
||||||
private final Set<String> onlineRemoteHwids = new HashSet<>();
|
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, String> cachedHostHwids = new ConcurrentHashMap<>();
|
||||||
private final ConcurrentHashMap<String, Long> cachedHostTimeout = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Long> cachedHostTimeout = new ConcurrentHashMap<>();
|
||||||
private final List<ReentrantLock> poolLock = new ArrayList<>(100);
|
|
||||||
|
|
||||||
private MapleSessionCoordinator() {
|
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) {
|
private static boolean attemptAccountAccess(int accountId, String nibbleHwid, boolean routineCheck) {
|
||||||
@@ -109,10 +102,6 @@ public class MapleSessionCoordinator {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Lock getCoodinatorLock(String remoteHost) {
|
|
||||||
return poolLock.get(Math.abs(remoteHost.hashCode()) % 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getSessionRemoteAddress(IoSession session) {
|
public static String getSessionRemoteAddress(IoSession session) {
|
||||||
return (String) session.getAttribute(MapleClient.CLIENT_REMOTE_ADDRESS);
|
return (String) session.getAttribute(MapleClient.CLIENT_REMOTE_ADDRESS);
|
||||||
@@ -152,9 +141,8 @@ public class MapleSessionCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String remoteHost = getSessionRemoteHost(session);
|
String remoteHost = getSessionRemoteHost(session);
|
||||||
Lock lock = getCoodinatorLock(remoteHost);
|
final InitializationResult initResult = sessionInit.initialize(remoteHost);
|
||||||
AntiMulticlientResult result = addToRemoteHostPoolWithRetries(lock, remoteHost);
|
switch (initResult.getAntiMulticlientResult()) {
|
||||||
switch (result) {
|
|
||||||
case REMOTE_PROCESSING -> {
|
case REMOTE_PROCESSING -> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -181,12 +169,7 @@ public class MapleSessionCoordinator {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
lock.lock();
|
sessionInit.finalize(remoteHost);
|
||||||
try {
|
|
||||||
pooledRemoteHosts.remove(remoteHost);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,10 +207,9 @@ public class MapleSessionCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String remoteHost = getSessionRemoteHost(session);
|
String remoteHost = getSessionRemoteHost(session);
|
||||||
final Lock lock = getCoodinatorLock(remoteHost);
|
InitializationResult initResult = sessionInit.initialize(remoteHost);
|
||||||
AntiMulticlientResult hostPoolAdditionResult = addToRemoteHostPoolWithRetries(lock, remoteHost);
|
if (initResult != InitializationResult.SUCCESS) {
|
||||||
if (hostPoolAdditionResult != AntiMulticlientResult.SUCCESS) {
|
return initResult.getAntiMulticlientResult();
|
||||||
return hostPoolAdditionResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -254,12 +236,7 @@ public class MapleSessionCoordinator {
|
|||||||
|
|
||||||
return AntiMulticlientResult.SUCCESS;
|
return AntiMulticlientResult.SUCCESS;
|
||||||
} finally {
|
} finally {
|
||||||
lock.lock();
|
sessionInit.finalize(remoteHost);
|
||||||
try {
|
|
||||||
pooledRemoteHosts.remove(remoteHost);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,10 +248,9 @@ public class MapleSessionCoordinator {
|
|||||||
return AntiMulticlientResult.SUCCESS;
|
return AntiMulticlientResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Lock lock = getCoodinatorLock(remoteHost);
|
final InitializationResult initResult = sessionInit.initialize(remoteHost);
|
||||||
AntiMulticlientResult hostPoolAdditionResult = addToRemoteHostPoolWithRetries(lock, remoteHost);
|
if (initResult != InitializationResult.SUCCESS) {
|
||||||
if (hostPoolAdditionResult != AntiMulticlientResult.SUCCESS) {
|
return initResult.getAntiMulticlientResult();
|
||||||
return hostPoolAdditionResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -303,48 +279,10 @@ public class MapleSessionCoordinator {
|
|||||||
|
|
||||||
return AntiMulticlientResult.SUCCESS;
|
return AntiMulticlientResult.SUCCESS;
|
||||||
} finally {
|
} finally {
|
||||||
lock.lock();
|
sessionInit.finalize(remoteHost);
|
||||||
try {
|
|
||||||
pooledRemoteHosts.remove(remoteHost);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
private static void associateHwidAccountIfAbsent(String remoteHwid, int accountId) {
|
||||||
try (Connection con = DatabaseConnection.getConnection()) {
|
try (Connection con = DatabaseConnection.getConnection()) {
|
||||||
List<String> hwids = SessionDAO.getHwidsForAccount(con, accountId);
|
List<String> hwids = SessionDAO.getHwidsForAccount(con, accountId);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user