EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=590)
-   -   Multiple LoginServer Connections (https://www.eqemulator.org/forums/showthread.php?t=30202)

Secrets 12-29-2009 10:58 AM

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);
        }
 }


pfyon 12-29-2009 06:00 PM

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.

Secrets 12-29-2009 07:03 PM

Quote:

Originally Posted by pfyon (Post 182130)
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.

pfyon 12-29-2009 10:39 PM

Quote:

Originally Posted by Secrets (Post 182136)
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.

Rogean 12-29-2009 11:25 PM

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.

Secrets 12-30-2009 07:43 AM

Quote:

Originally Posted by Rogean (Post 182153)
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.

trevius 12-31-2009 10:11 PM

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.

Xecuter 12-31-2009 10:58 PM

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.

Secrets 12-31-2009 11:02 PM

Quote:

Originally Posted by trevius (Post 182227)
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?

MNWatchdog 01-01-2010 01:46 AM

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.

Secrets 01-01-2010 11:46 AM

Quote:

Originally Posted by MNWatchdog (Post 182233)
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.

trevius 01-01-2010 05:42 PM

Yeah, adding a simple in game command that forces a query to be done to copy the information over shouldn't be too hard.

Secrets 01-01-2010 08:39 PM

Quote:

Originally Posted by trevius (Post 182238)
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.");


OscarGrouch05 02-04-2010 06:45 AM

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.

loglos 03-30-2010 01:59 PM

Quote:

Originally Posted by Secrets (Post 182230)
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. ;-)


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

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.