Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #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
  #2  
Old 12-29-2009, 06:00 PM
pfyon's Avatar
pfyon
Discordant
 
Join Date: Mar 2009
Location: Ottawa
Posts: 495
Default

So this is to get your server to be able to accept connections from two different login servers?

That would be pretty neat, I'd definitely use it so I could keep a login server for friends who don't have eqemu forum accounts or don't want to make one.
Reply With Quote
  #3  
Old 12-29-2009, 07:03 PM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

Quote:
Originally Posted by pfyon View Post
So this is to get your server to be able to accept connections from two different login servers?

That would be pretty neat, I'd definitely use it so I could keep a login server for friends who don't have eqemu forum accounts or don't want to make one.
Correct. Provided you actually *have* a second working LS. The EQEMuLoginServer from SVN crashes for me after logging in a client when there is a server on the list :/ The one image made works fine though.
Reply With Quote
  #4  
Old 12-29-2009, 10:39 PM
pfyon's Avatar
pfyon
Discordant
 
Join Date: Mar 2009
Location: Ottawa
Posts: 495
Default

Quote:
Originally Posted by Secrets View Post
Correct. Provided you actually *have* a second working LS. The EQEMuLoginServer from SVN crashes for me after logging in a client when there is a server on the list :/ The one image made works fine though.
Yeah, that's the one I used at one time too. It would be nice to get the one in the svn working too, and if your code works and gets fully integrated, then there wouldn't be any harm in having multiple loginservers around as long as the eqemulator one is used as a central one.
Reply With Quote
  #5  
Old 12-29-2009, 11:25 PM
Rogean's Avatar
Rogean
Administrator
 
Join Date: Jul 2003
Location: Massachusetts
Posts: 708
Default

Wouldn't work in combination with the public loginserver due to usernames/passwords. Would be an easier way to have a backup loginserver (A second public eqemulator central loginserver) for redundancy though.
__________________
EQEmulator Developer / Administrator
Reply With Quote
  #6  
Old 12-30-2009, 07:43 AM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

Quote:
Originally Posted by Rogean View Post
Wouldn't work in combination with the public loginserver due to usernames/passwords. Would be an easier way to have a backup loginserver (A second public eqemulator central loginserver) for redundancy though.
Very true; I didn't think of that. I guess having a secondary loginserver run from eqemulator.net like you stated would work. I'd need to re-do some of the code anyway to make it work like that.
Reply With Quote
  #7  
Old 12-31-2009, 10:11 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

I have always thought it would be great to have both a public LS connection as well as a private one up at all times in case the public one goes down.

The way I would do it would be to simply use the accounts table that already exists and force players to register on the public LS first and log into the server at least once via the public connection. Then, once their account name is in your DB, they can then issue a #password command to set a password for that account while in-game. The new password that they entered from in-game would then be hashed into the accounts table into the already existing password field. Once they have done that, they would have the option to login to your server via the private LS connection using the same account name and whatever password they set (preferably something different than their normal public LS password for security reasons). This should allow for both public and private LS's to use the same table for dealing with accounts, so you could play your same chars from either.

If you wanted to be able to register accounts for playing on your server directly from your Private LS and without having to register on the Public one, you could then just set a prefix to the usernames that get registered to help prevent (or at least heavily limit) the possibility of overlapping account names that might be registered publicly. So, for my server, it might prefix each username with sh_, so my login might be sh_trevius and so on.

Maybe I am missing something, but it doesn't seem like it would be too complex to allow a dual connection to both public and private LS without risking the possibility of too many conflicts.

Luckily, the current public LS is very stable and should be for a long time, hopefully. So, this isn't a huge concern. But, I do agree that it would be cool to have the option to be both public and private at the same time.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #8  
Old 12-31-2009, 10:58 PM
Xecuter
Fire Beetle
 
Join Date: Apr 2009
Location: washington
Posts: 13
Default

I'm in full agreement with trevius. Its unfortunate that in our community there are individuals who are so spitefull that they would do things such as the dos attacks and bring our community to its knees for days at a time. I don't see that stoping any time soon however.

I think dual login servers would be great for the community, there is power in redundancy. If everyone was running a dual log in server one idiots attack on the main login wouldn't hinder all of us.

Keep up the good ideas secrets / trevius. This is a great idea and i would love to see it come to completion.
__________________
Reply With Quote
  #9  
Old 12-31-2009, 11:02 PM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

Quote:
Originally Posted by trevius View Post
The way I would do it would be to simply use the accounts table that already exists and force players to register on the public LS first and log into the server at least once via the public connection. Then, once their account name is in your DB, they can then issue a #password command to set a password for that account while in-game. The new password that they entered from in-game would then be hashed into the accounts table into the already existing password field. Once they have done that, they would have the option to login to your server via the private LS connection using the same account name and whatever password they set (preferably something different than their normal public LS password for security reasons). This should allow for both public and private LS's to use the same table for dealing with accounts, so you could play your same chars from either.
The issue with this is the EQEmuLoginServer on SVN is 1) Windows Only, and 2) horribadly broken. I kept getting heap corruption when I logged in. KLS can't reproduce it, I can't figure it out, so unless anyone else wants to take a look at it, go for it.

But the issue is, you'd need to code the LS to take the sha1 passwords from the accounts table as opposed to the login_accounts table. It's a great idea but if the LS is not even working... well, what do we do?
Reply With Quote
  #10  
Old 01-01-2010, 01:46 AM
MNWatchdog
Hill Giant
 
Join Date: Feb 2006
Posts: 179
Default

Why not just code in game support so people can set a PW for support of Images login server software to be used as a alternate/backup LS.
Reply With Quote
  #11  
Old 01-01-2010, 11:46 AM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

Quote:
Originally Posted by MNWatchdog View Post
Why not just code in game support so people can set a PW for support of Images login server software to be used as a alternate/backup LS.
Actually, now that I think about it... copying the account name and doing all the work for the LS in-game may actually work, hah. I'll look into it.
Reply With Quote
  #12  
Old 01-01-2010, 05:42 PM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

Yeah, adding a simple in game command that forces a query to be done to copy the information over shouldn't be too hard.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #13  
Old 01-01-2010, 08:39 PM
Secrets's Avatar
Secrets
Demi-God
 
Join Date: May 2007
Location: b
Posts: 1,450
Default

Quote:
Originally Posted by trevius View Post
Yeah, adding a simple in game command that forces a query to be done to copy the information over shouldn't be too hard.
Yup, tested it and it works flawlessly with Image's LS.

This has no conflicts as far as I know in regards to account names, and it preserves the other LS' ID to sync the two. The #setpass command in-game is reworked to allow only the character who used the command's account to be changed, and the only parameter for it now is password.

Enjoy!

Code:
Index: common/database.cpp
===================================================================
--- common/database.cpp	(revision 1068)
+++ common/database.cpp	(working copy)
@@ -382,7 +382,7 @@
 	return false;
 }
 
-bool Database::SetLocalPassword(int32 accid, const char* password) {
+bool Database::SetLocalPassword(int32 accid, const char* password, const char* name, int32 lsid ) {
 	char errbuf[MYSQL_ERRMSG_SIZE];
     char *query = 0;
 
@@ -392,6 +392,12 @@
 		return false;
 	}
 
+	if (!RunQuery(query, MakeAnyLenString(&query, "REPLACE INTO `login_accounts` SET id = %i, name='%s', password=MD5('%s');", lsid, name, password), errbuf)) {
+		cerr << "Error in SetLocalPassword query '" << query << "' " << errbuf << endl;
+		safe_delete_array(query);
+		return false;
+	}
+
 	safe_delete_array(query);
 	return true;
 }
Index: common/database.h
===================================================================
--- common/database.h	(revision 1068)
+++ common/database.h	(working copy)
@@ -215,7 +215,7 @@
 	int32	CreateAccount(const char* name, const char* password, sint16 status, int32 lsaccount_id = 0);
 	bool	DeleteAccount(const char* name);
  	bool	SetAccountStatus(const char* name, sint16 status);
-	bool	SetLocalPassword(uint32 accid, const char* password);
+	bool	SetLocalPassword(uint32 accid, const char* password, const char* name, int32 lsid);
 	int32	GetAccountIDFromLSID(int32 iLSID, char* oAccountName = 0, sint16* oStatus = 0);
 	bool	UpdateLiveChar(char* charname,int32 lsaccount_id);
 	bool	GetLiveChar(int32 account_id, char* cname);
Index: common/EQEmuConfig.cpp
===================================================================
--- common/EQEmuConfig.cpp	(revision 1068)
+++ 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 1068)
+++ 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 1068)
+++ 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 1068)
+++ 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/console.cpp
===================================================================
--- world/console.cpp	(revision 1068)
+++ world/console.cpp	(working copy)
@@ -454,23 +454,6 @@
 			else if (strcasecmp(sep.arg[0], "ping") == 0) {
 				// do nothing
 			}
-			else if (strcasecmp(sep.arg[0], "setpass") == 0 && admin >= consolePassStatus) {
-				if (sep.argnum != 2)
-					SendMessage(1, "Format: setpass accountname password");
-				else {
-
-					sint16 tmpstatus = 0;
-					int32 tmpid = database.GetAccountIDByName(sep.arg[1], &tmpstatus);
-					if (!tmpid)
-						SendMessage(1, "Error: Account not found");
-					else if (tmpstatus > admin)
-						SendMessage(1, "Cannot change password: Account's status is higher than yours");
-					else if (database.SetLocalPassword(tmpid, sep.arg[2]))
-						SendMessage(1, "Password changed.");
-					else
-						SendMessage(1, "Error changing password."); 
-				}
-			}
 			else if (strcasecmp(sep.arg[0], "uptime") == 0) {
 				if (sep.IsNumber(1) && atoi(sep.arg[1]) > 0) {
 					ServerPacket* pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct));
Index: world/LoginServer.cpp
===================================================================
--- world/LoginServer.cpp	(revision 1068)
+++ 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 1068)
+++ 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 1068)
+++ 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);
 	}
 }
Index: zone/command.cpp
===================================================================
--- zone/command.cpp	(revision 1068)
+++ zone/command.cpp	(working copy)
@@ -2374,16 +2374,14 @@
 
 void command_setpass(Client *c, const Seperator *sep)
 {
-	if(sep->argnum != 2)
-		c->Message(0, "Format: #setpass accountname password");
+	if(sep->argnum != 1)
+		c->Message(0, "Format: #setpass password");
 	else {
-		sint16 tmpstatus = 0;
-		int32 tmpid = database.GetAccountIDByName(sep->arg[1], &tmpstatus);
-		if (!tmpid)
+		int32 lsid = c->LSAccountID();
+		int32 acctid = database.GetAccountIDByChar(c->GetName());
+		if (!acctid)
 			c->Message(0, "Error: Account not found");
-		else if (tmpstatus > c->Admin())
-			c->Message(0, "Cannot change password: Account's status is higher than yours");
-		else if (database.SetLocalPassword(tmpid, sep->arg[2]))
+		else if (database.SetLocalPassword(acctid, sep->arg[1], c->AccountName(), lsid))
 			c->Message(0, "Password changed.");
 		else
 			c->Message(0, "Error changing password.");
Reply With Quote
  #14  
Old 02-04-2010, 06:45 AM
OscarGrouch05
Sarnak
 
Join Date: Apr 2008
Posts: 71
Default

xecutter Keep up the good ideas secrets / trevius. that he does vary well if do say so myself.

a two server login is vary easy to setup only problem i would see is server name would have to be under a different name.
as well as running two database's or combind them as one together.

are you talking like in one client install or two clients running?
or like two data base's with two client's running using diffent port's?

the other question would be to combind the chat and messages and have only server name diffent that would work too.
Reply With Quote
  #15  
Old 03-30-2010, 01:59 PM
loglos
Sarnak
 
Join Date: Feb 2008
Posts: 51
Default

Quote:
Originally Posted by Secrets View Post
I kept getting heap corruption when I logged in. KLS can't reproduce it, I can't figure it out, so unless anyone else wants to take a look at it, go for it.
Are you running win7 64bit? I am and was getting the heap issue also. Everytime I logged in. I just grabbed the source and recompiled and now it works fine.

I have other problems, but the login server is no longer having issues.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 04:02 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3