View Single Post
  #1  
Old 12-29-2009, 10:58 AM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default Multiple LoginServer Connections

Here's what I have been working on lately, it's basically a hackjob copypaste, but it works which is the important part.

It is basically connecting world to two loginservers, while having the two LSIDs seperate from each other using MySQL.

The trick to making this work is to make the LoginServer ID in the EQEmuLoginServer DB greater than 6 million on autoincrement. With 128,000 members on eqemulator, each having 3 loginserver accounts, that comes out to about 600,000 accounts. With 6 million on autoincrement, EQEmu will never reach the LS accounts from your server, and even if they do, it's just a query away for adding more + incrementing the existing.

TODO: Add manual reconnect for second connection.

Here's what I got so far:

Code:
Index: common/EQEmuConfig.cpp
===================================================================
--- common/EQEmuConfig.cpp	(revision 1064)
+++ common/EQEmuConfig.cpp	(working copy)
@@ -70,6 +70,21 @@
 		text=ParseTextBlock(sub_ele,"password",true);
 		if (text)
 			LoginPassword=text;
+		text=ParseTextBlock(sub_ele,"host2",true);
+		if (text)
+			LoginHost2=text;
+
+		text=ParseTextBlock(sub_ele,"port2",true);
+		if (text)
+			LoginPort2=atoi(text);
+		
+		text=ParseTextBlock(sub_ele,"account2",true);
+		if (text)
+			LoginAccount2=text;
+
+		text=ParseTextBlock(sub_ele,"password2",true);
+		if (text)
+			LoginPassword2=text;
 	}
 	
 	// Check for locked
@@ -305,6 +320,14 @@
 		return(LoginPassword);
 	if(var_name == "LoginPort")
 		return(itoa(LoginPort));
+	if(var_name == "LoginHost2")
+		return(LoginHost2);
+	if(var_name == "LoginAccount2")
+		return(LoginAccount2);
+	if(var_name == "LoginPassword2")
+		return(LoginPassword2);
+	if(var_name == "LoginPort2")
+		return(itoa(LoginPort2));
 	if(var_name == "Locked")
 		return(Locked?"true":"false");
 	if(var_name == "WorldTCPPort")
@@ -377,6 +400,10 @@
 	cout << "LoginAccount = " << LoginAccount << endl;
 	cout << "LoginPassword = " << LoginPassword << endl;
 	cout << "LoginPort = " << LoginPort << endl;
+	cout << "LoginHost2 = " << LoginHost2 << endl;
+	cout << "LoginAccount2 = " << LoginAccount2 << endl;
+	cout << "LoginPassword2 = " << LoginPassword2 << endl;
+	cout << "LoginPort2 = " << LoginPort2 << endl;
 	cout << "Locked = " << Locked << endl;
 	cout << "WorldTCPPort = " << WorldTCPPort << endl;
 	cout << "WorldIP = " << WorldIP << endl;
Index: common/EQEmuConfig.h
===================================================================
--- common/EQEmuConfig.h	(revision 1064)
+++ common/EQEmuConfig.h	(working copy)
@@ -33,6 +33,10 @@
 	string LoginAccount;
 	string LoginPassword;
 	uint16 LoginPort;
+	string LoginHost2;
+	string LoginAccount2;
+	string LoginPassword2;
+	uint16 LoginPort2;
 	bool Locked;
 	uint16 WorldTCPPort;
 	string WorldIP;
@@ -109,6 +113,8 @@
 		// Login server
 		LoginHost="eqemulator.net";
 		LoginPort=5998;
+		LoginHost2="eqemulator.net2";
+		LoginPort2=5999;
 
 		// World
 		Locked=false;
Index: world/client.cpp
===================================================================
--- world/client.cpp	(revision 1064)
+++ world/client.cpp	(working copy)
@@ -298,6 +298,7 @@
 					strcpy(join->key,GetLSKey());
 					join->lsaccount_id = GetLSID();
 					loginserver.SendPacket(pack);
+					loginserver.SendPacket2(pack);
 					safe_delete(pack);
 				}
 
@@ -795,6 +796,7 @@
 			strcpy(logout->key,GetLSKey());
 			logout->lsaccount_id = GetLSID();
 			loginserver.SendPacket(pack);
+			loginserver.SendPacket2(pack);
 			safe_delete(pack);
 		}
 		clog(WORLD__CLIENT,"Client disconnected (not active in process)");
Index: world/cliententry.cpp
===================================================================
--- world/cliententry.cpp	(revision 1064)
+++ world/cliententry.cpp	(working copy)
@@ -126,7 +126,7 @@
 		zone->count=iZS->NumPlayers();
 		zone->zone = iZS->GetZoneID();
 		zone->zone_wid = iZS->GetID();
-		loginserver.SendPacket(pack);
+		loginserver.SendPacket2(pack);
 		safe_delete(pack);
 	}
 }
@@ -141,6 +141,7 @@
 		zonechange->from = ztz->current_zone_id;
 		zonechange->to = ztz->requested_zone_id;
 		loginserver.SendPacket(pack);
+		loginserver.SendPacket2(pack);
 		safe_delete(pack);
 	}
 }
Index: world/LoginServer.cpp
===================================================================
--- world/LoginServer.cpp	(revision 1064)
+++ world/LoginServer.cpp	(working copy)
@@ -83,10 +83,13 @@
 	LoginServerPort = iPort;
 	tcpc = new EmuTCPConnection(true);
 	tcpc->SetPacketMode(EmuTCPConnection::packetModeLogin);
+	tcpc2 = new EmuTCPConnection(true);
+	tcpc2->SetPacketMode(EmuTCPConnection::packetModeLogin);
 }
 
 LoginServer::~LoginServer() {
 	delete tcpc;
+	delete tcpc2;
 }
 
 bool LoginServer::Process() {
@@ -98,6 +101,7 @@
     
 	/************ Get all packets from packet manager out queue and process them ************/
 	ServerPacket *pack = 0;
+	ServerPacket *pack2 = 0;
 	while((pack = tcpc->PopPacket()))
 	{
 		_log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode);
@@ -196,6 +200,104 @@
 		delete pack;
 	}
 
+		while((pack2 = tcpc2->PopPacket()))
+	{
+		_log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack2->opcode);
+		_hex(WORLD__LS_TRACE,pack2->pBuffer,pack2->size);
+
+		switch(pack2->opcode) {
+		case 0:
+			break;
+		case ServerOP_KeepAlive: {
+			// ignore this
+			break;
+		}
+		case ServerOP_UsertoWorldReq: {
+			UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack2->pBuffer;	
+			int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
+			sint16 status = database.CheckStatus(id);
+
+			ServerPacket* outpack = new ServerPacket;
+			outpack->opcode = ServerOP_UsertoWorldResp;
+			outpack->size = sizeof(UsertoWorldResponse_Struct);
+			outpack->pBuffer = new uchar[outpack->size];
+			memset(outpack->pBuffer, 0, outpack->size);
+			UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
+			utwrs->lsaccountid = utwr->lsaccountid;
+			utwrs->ToID = utwr->FromID;
+
+			if(Config->Locked == true)
+			{
+				if((status == 0 || status < 100) && (status != -2 || status != -1))
+					utwrs->response = 0;
+				if(status >= 100)
+					utwrs->response = 1;
+			}
+			else {
+				utwrs->response = 1;
+			}
+
+			sint32 x = Config->MaxClients;
+			if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
+				utwrs->response = -3;
+
+			if(status == -1)
+				utwrs->response = -1;
+			if(status == -2)
+				utwrs->response = -2;
+
+			utwrs->worldid = utwr->worldid;
+			SendPacket2(outpack);
+			delete outpack;
+			break;
+		}
+		case ServerOP_LSClientAuth: {
+			ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack2->pBuffer;
+
+			if (RuleI(World, AccountSessionLimit) >= 0) {
+				// Enforce the limit on the number of characters on the same account that can be 
+				// online at the same time.
+				client_list.EnforceSessionLimit(slsca->lsaccount_id); 
+			}
+
+			client_list.CLEAdd(slsca->lsaccount_id, slsca->name, slsca->key, slsca->worldadmin, slsca->ip, slsca->local);
+			break;
+		}
+		case ServerOP_LSFatalError: {
+#ifndef IGNORE_LS_FATAL_ERROR
+			WorldConfig::DisableLoginserver();
+			_log(WORLD__LS_ERR, "Login server responded with FatalError. Disabling reconnect.");
+#else
+		_log(WORLD__LS_ERR, "Login server responded with FatalError.");
+#endif
+			if (pack2->size > 1) {
+				_log(WORLD__LS_ERR, "     %s",pack2->pBuffer);
+			}
+			break;
+		}
+		case ServerOP_SystemwideMessage: {
+			ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack2->pBuffer;
+			zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message);
+			break;
+		}
+		case ServerOP_LSRemoteAddr: {
+			if (!Config->WorldAddress.length()) {
+				WorldConfig::SetWorldAddress((char *)pack2->pBuffer);
+				_log(WORLD__LS, "Loginserver provided %s as world address",pack2->pBuffer);
+			}
+			break;
+		}
+		default:
+		{
+			_log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack2->opcode,pack->size);
+DumpPacket(pack2->pBuffer, pack2->size);
+			break;
+		}
+		}
+
+		delete pack2;
+		}
+
 	return true;
 }
 
@@ -206,7 +308,7 @@
 	void *AutoInitLoginServer(void *tmp) {
 #endif
 	srand(time(NULL));
-	if (loginserver.ConnectReady()) {
+	if (loginserver.ConnectReady() && loginserver.ConnectReady2()) {
 		InitLoginServer();
 	}
 #ifndef WIN32
@@ -227,11 +329,11 @@
 	}
 
 	AttemptingConnect = true;
-	loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort);
+	loginserver.Connect(Config->LoginHost.c_str(), Config->LoginPort, Config->LoginHost2.c_str(), Config->LoginPort2);
 	return true;
 }
 
-bool LoginServer::Connect(const char* iAddress, int16 iPort) {
+bool LoginServer::Connect(const char* iAddress, int16 iPort, const char* iAddress2, int16 iPort2) {
 	char tmp[25];
 	if(database.GetVariable("loginType",tmp,sizeof(tmp)) && strcasecmp(tmp,"MinILogin") == 0){
 		minilogin = true;
@@ -264,8 +366,28 @@
 		return false;
 	}
 
-	if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) {
+	if (iAddress2 == 0) {
+		_log(WORLD__LS_ERR, "Null address given to LoginServer::Connect");
+		return false;
+	}
+	else {
+		if ((LoginServerIP2 = ResolveIP(iAddress2, errbuf)) == 0) {
+			_log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",iAddress2);
+			return false;
+		}
+	}
+	if (iPort2 != 0)
+		LoginServerPort2 = iPort2;
+
+	if (LoginServerIP == 0 || LoginServerPort == 0) {
+		_log(WORLD__LS_ERR, "LoginServer::Connect: Connect info incomplete, cannot connect");
+		return false;
+	}
+
+
+	if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf) && tcpc2->ConnectIP(LoginServerIP2, LoginServerPort2)) {
 		_log(WORLD__LS, "Connected to Loginserver: %s:%d",iAddress,LoginServerPort);
+		_log(WORLD__LS, "Connected to Alternative Loginserver: %s:%d",iAddress2,LoginServerPort2);
 		if (minilogin)
 			SendInfo();
 		else
@@ -279,6 +401,8 @@
 		return false;
 	}
 }
+
+
 void LoginServer::SendInfo() {
 	const WorldConfig *Config=WorldConfig::get();
 
@@ -295,7 +419,23 @@
 	strcpy(lsi->password, Config->LoginPassword.c_str());
 	strcpy(lsi->address, Config->WorldAddress.c_str());
 	SendPacket(pack);
+
+
+	ServerPacket* pack2 = new ServerPacket;
+	pack2->opcode = ServerOP_LSInfo;
+	pack2->size = sizeof(ServerLSInfo_Struct);
+	pack2->pBuffer = new uchar[pack2->size];
+	memset(pack2->pBuffer, 0, pack2->size);
+	ServerLSInfo_Struct* lsi2 = (ServerLSInfo_Struct*) pack2->pBuffer;
+	strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
+	strcpy(lsi2->serverversion, CURRENT_VERSION);
+	strcpy(lsi2->name, Config->LongName.c_str());
+	strcpy(lsi2->account, Config->LoginAccount2.c_str());
+	strcpy(lsi2->password, Config->LoginPassword2.c_str());
+	strcpy(lsi2->address, Config->WorldAddress.c_str());
+	SendPacket2(pack2);
 	delete pack;
+	delete pack2;
 }
 
 void LoginServer::SendNewInfo() {
@@ -323,7 +463,32 @@
 		WorldConfig::SetLocalAddress(lsi->local_address);
 	}
 	SendPacket(pack);
+
+	ServerPacket* pack2 = new ServerPacket;
+	pack2->opcode = ServerOP_NewLSInfo;
+	pack2->size = sizeof(ServerNewLSInfo_Struct);
+	pack2->pBuffer = new uchar[pack2->size];
+	memset(pack2->pBuffer, 0, pack2->size);
+	ServerNewLSInfo_Struct* lsi2 = (ServerNewLSInfo_Struct*) pack2->pBuffer;
+	strcpy(lsi2->protocolversion, EQEMU_PROTOCOL_VERSION);
+	strcpy(lsi2->serverversion, CURRENT_VERSION);
+	strcpy(lsi2->name, Config->LongName.c_str());
+	strcpy(lsi2->shortname, Config->ShortName.c_str());
+	strcpy(lsi2->account, Config->LoginAccount.c_str());
+	strcpy(lsi2->password, Config->LoginPassword.c_str());
+	if (Config->WorldAddress.length())
+		strcpy(lsi2->remote_address, Config->WorldAddress.c_str());
+	if (Config->LocalAddress.length())
+		strcpy(lsi2->local_address, Config->LocalAddress.c_str());
+	else {
+		tcpc2->GetSockName(lsi2->local_address,&port);
+		WorldConfig::SetLocalAddress(lsi2->local_address);
+	}
+	SendPacket(pack);
+
+	SendPacket2(pack);
 	delete pack;
+	delete pack2;
 }
 
 void LoginServer::SendStatus() {
@@ -345,6 +510,7 @@
 	lss->num_zones = numzones;
 	lss->num_players = numplayers;
 	SendPacket(pack);
+	SendPacket2(pack);
 	delete pack;
 }
 
Index: world/LoginServer.h
===================================================================
--- world/LoginServer.h	(revision 1064)
+++ world/LoginServer.h	(working copy)
@@ -39,22 +39,28 @@
     ~LoginServer();
 
 	bool Process();
-	bool Connect(const char* iAddress = 0, int16 iPort = 0);
+	bool Connect(const char* iAddress = 0, int16 iPort = 0, const char *iAddress2 = 0, int16 iPort2 = 0);
 
 	void SendInfo();
 	void SendNewInfo();
 	void SendStatus();
 
 	void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
+	void SendPacket2(ServerPacket* pack) { tcpc2->SendPacket(pack); }
 	bool ConnectReady() { return tcpc->ConnectReady(); }
+	bool ConnectReady2() { return tcpc2->ConnectReady(); }
 	bool Connected() { return tcpc->Connected(); }
+	bool Connected2() { return tcpc2->Connected(); }
 	bool MiniLogin() { return minilogin; }
 
 private:
 	bool minilogin;
 	EmuTCPConnection* tcpc;
+	EmuTCPConnection* tcpc2;
 	int32	LoginServerIP;
 	int16	LoginServerPort;
+	int32	LoginServerIP2;
+	int16	LoginServerPort2;
 
 	Timer statusupdate_timer;
 };
Index: world/zoneserver.cpp
===================================================================
--- world/zoneserver.cpp	(revision 1064)
+++ world/zoneserver.cpp	(working copy)
@@ -120,6 +120,7 @@
 			zsd->zone = zoneid;
 		zsd->zone_wid = GetID();
 		loginserver.SendPacket(pack);
+		loginserver.SendPacket2(pack);
 		safe_delete(pack);
 	}
 }
@@ -140,6 +141,7 @@
 		bootup->zone_wid = GetID();
 		bootup->instance = instanceid;
 		loginserver.SendPacket(pack);
+		loginserver.SendPacket2(pack);
 		safe_delete(pack);
 	}
 }
@@ -155,6 +157,7 @@
 		sleep->zone = zoneid;
 		sleep->zone_wid = GetID();
 		loginserver.SendPacket(pack);
+		loginserver.SendPacket2(pack);
 		safe_delete(pack);
 	}
 }
Reply With Quote