bool ClientList::SendPacket(const char* to, ServerPacket* pack) { if (to == 0 || to[0] == 0) { zoneserver_list.SendPacket(pack); return true; } else if (to[0] == '*') { // Cant send a packet to a console.... return false; } else { ClientListEntry* cle = FindCharacter(to); if (cle != nullptr) { if (cle->Server() != nullptr) { cle->Server()->SendPacket(pack); return true; } return false; } else { ZoneServer* zs = zoneserver_list.FindByName(to); if (zs != nullptr) { zs->SendPacket(pack); return true; } return false; } } return false; }
void handle_rc_relay(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector<std::string> ¶ms) { std::string error; std::map<std::string, std::string> res; uint32 zone_id = 0; uint32 instance_id = 0; ZoneServer *zs = nullptr; if(params.size() < 2) { error = "Missing zone relay params"; RemoteCallResponse(connection_id, request_id, res, error); return; } zone_id = (uint32)atoi(params[0].c_str()); instance_id = (uint32)atoi(params[1].c_str()); if(!zone_id && !instance_id) { error = "Zone not booted"; RemoteCallResponse(connection_id, request_id, res, error); return; } if(instance_id) { zs = zoneserver_list.FindByInstanceID(instance_id); } else { zs = zoneserver_list.FindByZoneID(zone_id); } if(!zs) { error = "Zone server not found"; RemoteCallResponse(connection_id, request_id, res, error); return; } uint32 sz = (uint32)(request_id.size() + connection_id.size() + method.size() + 3 + 16); uint32 p_sz = (uint32)params.size() - 2; for(uint32 i = 0; i < p_sz; ++i) { auto ¶m = params[i + 2]; sz += (uint32)param.size(); sz += 5; } ServerPacket *pack = new ServerPacket(ServerOP_WIRemoteCall, sz); pack->WriteUInt32((uint32)request_id.size()); pack->WriteString(request_id.c_str()); pack->WriteUInt32((uint32)connection_id.size()); pack->WriteString(connection_id.c_str()); pack->WriteUInt32((uint32)method.size()); pack->WriteString(method.c_str()); pack->WriteUInt32(p_sz); for(uint32 i = 0; i < p_sz; ++i) { auto ¶m = params[i + 2]; pack->WriteUInt32((uint32)param.size()); pack->WriteString(param.c_str()); } zs->SendPacket(pack); safe_delete(pack); }
void Adventure::SetStatus(AdventureStatus new_status) { if(new_status == AS_WaitingForPrimaryEndTime) { status = new_status; safe_delete(current_timer); current_timer = new Timer(adventure_template->duration * 1000); database.SetInstanceDuration(instance_id, adventure_template->duration + 60); ServerPacket *pack = new ServerPacket(ServerOP_InstanceUpdateTime, sizeof(ServerInstanceUpdateTime_Struct)); ServerInstanceUpdateTime_Struct *ut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer; ut->instance_id = instance_id; ut->new_duration = adventure_template->duration + 60; pack->Deflate(); zoneserver_list.SendPacket(0, instance_id, pack); safe_delete(pack); } else if(new_status == AS_WaitingForSecondaryEndTime) { status = new_status; safe_delete(current_timer); current_timer = new Timer(1800000); database.SetInstanceDuration(instance_id, 1860); ServerPacket *pack = new ServerPacket(ServerOP_InstanceUpdateTime, sizeof(ServerInstanceUpdateTime_Struct)); ServerInstanceUpdateTime_Struct *ut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer; ut->instance_id = instance_id; ut->new_duration = 1860; pack->Deflate(); zoneserver_list.SendPacket(0, instance_id, pack); safe_delete(pack); } else if(new_status == AS_Finished) { status = new_status; safe_delete(current_timer); current_timer = new Timer(1800000); database.SetInstanceDuration(instance_id, 1800); ServerPacket *pack = new ServerPacket(ServerOP_InstanceUpdateTime, sizeof(ServerInstanceUpdateTime_Struct)); ServerInstanceUpdateTime_Struct *ut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer; ut->instance_id = instance_id; ut->new_duration = 1860; pack->Deflate(); zoneserver_list.SendPacket(0, instance_id, pack); safe_delete(pack); } else { return; } list<string>::iterator iter = players.begin(); while(iter != players.end()) { adventure_manager.GetAdventureData((*iter).c_str()); iter++; } }
map<string,string> EQW::GetZoneDetails(Const_char *zone_ref) { map<string,string> res; ZoneServer *zs = zoneserver_list.FindByID(atoi(zone_ref)); if(zs == NULL) { res["error"] = "Invalid zone."; return(res); } res["type"] = zs->IsStaticZone()?"static":"dynamic"; res["zone_id"] = itoa(zs->GetZoneID()); res["launch_name"] = zs->GetLaunchName(); res["launched_name"] = zs->GetLaunchedName(); res["short_name"] = zs->GetZoneName(); res["long_name"] = zs->GetZoneLongName(); res["port"] = itoa(zs->GetCPort()); res["player_count"] = itoa(zs->NumPlayers()); //this isnt gunna work for dynamic zones... res["launcher"] = ""; if(zs->GetZoneID() != 0) { LauncherLink *ll = launcher_list.FindByZone(zs->GetLaunchName()); if(ll != NULL) res["launcher"] = ll->GetName(); } return(res); }
void ZoneServer::SendGroupIDs() { ServerPacket* pack = new ServerPacket(ServerOP_GroupIDReply, sizeof(ServerGroupIDReply_Struct)); ServerGroupIDReply_Struct* sgi = (ServerGroupIDReply_Struct*)pack->pBuffer; zoneserver_list.NextGroupIDs(sgi->start, sgi->end); SendPacket(pack); delete pack; }
void handle_rc_get_zone_info(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector<std::string> ¶ms) { std::string error; std::map<std::string, std::string> res; if(params.size() != 1) { error = "Expected only one zone_id."; RemoteCallResponse(connection_id, request_id, res, error); return; } ZoneServer *zs = zoneserver_list.FindByID(atoi(params[0].c_str())); if(zs == nullptr) { error = "Invalid zone"; RemoteCallResponse(connection_id, request_id, res, error); return; } res["type"] = zs->IsStaticZone() ? "static" : "dynamic"; res["zone_id"] = itoa(zs->GetZoneID()); res["instance_id"] = itoa(zs->GetInstanceID()); res["launch_name"] = zs->GetLaunchName(); res["launched_name"] = zs->GetLaunchedName(); res["short_name"] = zs->GetZoneName(); res["long_name"] = zs->GetZoneLongName(); res["port"] = itoa(zs->GetCPort()); res["player_count"] = itoa(zs->NumPlayers()); RemoteCallResponse(connection_id, request_id, res, error); }
void WorldGuildManager::SendGuildDelete(uint32 guild_id) { Log(Logs::Detail, Logs::Guilds, "Broadcasting guild delete for guild %d to world", guild_id); auto pack = new ServerPacket(ServerOP_DeleteGuild, sizeof(ServerGuildID_Struct)); ServerGuildID_Struct *s = (ServerGuildID_Struct *) pack->pBuffer; s->guild_id = guild_id; zoneserver_list.SendPacket(pack); safe_delete(pack); }
void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) { ServerPacket* pack = new ServerPacket(ServerOP_ChangeWID, sizeof(ServerChangeWID_Struct)); ServerChangeWID_Struct* scw = (ServerChangeWID_Struct*) pack->pBuffer; scw->charid = iCharID; scw->newwid = iWID; zoneserver_list.SendPacket(pack); delete pack; }
void WorldGuildManager::SendCharRefresh(uint32 old_guild_id, uint32 guild_id, uint32 charid) { Log(Logs::Detail, Logs::Guilds, "Broadcasting char refresh for %d from guild %d to world", charid, guild_id); auto pack = new ServerPacket(ServerOP_GuildCharRefresh, sizeof(ServerGuildCharRefresh_Struct)); ServerGuildCharRefresh_Struct *s = (ServerGuildCharRefresh_Struct *) pack->pBuffer; s->guild_id = guild_id; s->old_guild_id = old_guild_id; s->char_id = charid; zoneserver_list.SendPacket(pack); safe_delete(pack); }
void ClientList::SendOnlineGuildMembers(uint32 FromID, uint32 GuildID) { int PacketLength = 8; uint32 Count = 0; ClientListEntry* from = this->FindCLEByCharacterID(FromID); if(!from) { _log(WORLD__CLIENT_ERR,"Invalid client. FromID=%i GuildID=%i", FromID, GuildID); return; } LinkedListIterator<ClientListEntry*> Iterator(clientlist); Iterator.Reset(); while(Iterator.MoreElements()) { ClientListEntry* CLE = Iterator.GetData(); if(CLE && (CLE->GuildID() == GuildID)) { PacketLength += (strlen(CLE->name()) + 5); ++Count; } Iterator.Advance(); } Iterator.Reset(); ServerPacket* pack = new ServerPacket(ServerOP_OnlineGuildMembersResponse, PacketLength); char *Buffer = (char *)pack->pBuffer; VARSTRUCT_ENCODE_TYPE(uint32, Buffer, FromID); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, Count); while(Iterator.MoreElements()) { ClientListEntry* CLE = Iterator.GetData(); if(CLE && (CLE->GuildID() == GuildID)) { VARSTRUCT_ENCODE_STRING(Buffer, CLE->name()); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, CLE->zone()); } Iterator.Advance(); } zoneserver_list.SendPacket(from->zone(), from->instance(), pack); safe_delete(pack); }
void WorldGuildManager::SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation) { Log(Logs::Detail, Logs::Guilds, "Broadcasting guild refresh for %d, changes: name=%d, motd=%d, rank=d, relation=%d", guild_id, name, motd, rank, relation); auto pack = new ServerPacket(ServerOP_RefreshGuild, sizeof(ServerGuildRefresh_Struct)); ServerGuildRefresh_Struct *s = (ServerGuildRefresh_Struct *) pack->pBuffer; s->guild_id = guild_id; s->name_change = name; s->motd_change = motd; s->rank_change = rank; s->relation_change = relation; zoneserver_list.SendPacket(pack); safe_delete(pack); }
void handle_rc_list_zones(const std::string &method, const std::string &connection_id, const std::string &request_id, const std::vector<std::string> ¶ms) { std::vector<uint32> zones; zoneserver_list.GetZoneIDList(zones); std::map<std::string, std::string> res; uint32 sz = (uint32)zones.size(); for(uint32 i = 0; i < sz; ++i) { res[itoa(i)] = (itoa(zones[i])); } std::string error; RemoteCallResponse(connection_id, request_id, res, error); }
//returns an array of zone_refs (opaque) vector<string> EQW::ListBootedZones() { vector<string> res; vector<int32> zones; zoneserver_list.GetZoneIDList(zones); vector<int32>::iterator cur, end; cur = zones.begin(); end = zones.end(); for(; cur != end; cur++) { res.push_back(itoa(*cur)); } return(res); }
ZoneServer::ZoneServer(EmuTCPConnection* itcpc) : WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) { ID = zoneserver_list.GetNextID(); memset(zone_name, 0, sizeof(zone_name)); memset(compiled, 0, sizeof(compiled)); zoneID = 0; instanceID = 0; memset(clientaddress, 0, sizeof(clientaddress)); clientport = 0; BootingUp = false; authenticated = false; staticzone = false; pNumPlayers = 0; }
//Account Limiting Code to limit the number of characters allowed on from a single account at once. void ClientList::EnforceSessionLimit(int32 iLSAccountID) { ClientListEntry* ClientEntry = 0; LinkedListIterator<ClientListEntry*> iterator(clientlist, BACKWARD); int CharacterCount = 0; iterator.Reset(); while(iterator.MoreElements()) { ClientEntry = iterator.GetData(); if ((ClientEntry->LSAccountID() == iLSAccountID) && ((ClientEntry->Admin() <= (RuleI(World, ExemptAccountLimitStatus))) || (RuleI(World, ExemptAccountLimitStatus) < 0))) { CharacterCount++; if (CharacterCount >= (RuleI(World, AccountSessionLimit))){ // If we have a char name, they are in a zone, so send a kick to the zone server if(strlen(ClientEntry->name())) { ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer; strcpy(skp->adminname, "SessionLimit"); strcpy(skp->name, ClientEntry->name()); skp->adminrank = 255; zoneserver_list.SendPacket(pack); safe_delete(pack); } ClientEntry->SetOnline(CLE_Status_Offline); iterator.RemoveCurrent(); continue; } } iterator.Advance(); } }
void Adventure::SendAdventureMessage(uint32 type, const char *msg) { ServerPacket *pack = new ServerPacket(ServerOP_EmoteMessage, sizeof(ServerEmoteMessage_Struct) + strlen(msg) + 1); ServerEmoteMessage_Struct *sms = (ServerEmoteMessage_Struct*)pack->pBuffer; sms->type = type; strcpy(sms->message, msg); list<string>::iterator iter = players.begin(); while(iter != players.end()) { ClientListEntry *current = client_list.FindCharacter((*iter).c_str()); if(current) { strcpy(sms->to, (*iter).c_str()); zoneserver_list.SendPacket(current->zone(), current->instance(), pack); } iter++; } delete pack; }
bool LoginServer::Connect() { char tmp[25]; if(database.GetVariable("loginType",tmp,sizeof(tmp)) && strcasecmp(tmp,"MinILogin") == 0){ minilogin = true; _log(WORLD__LS, "Setting World to MiniLogin Server type"); } else minilogin = false; if (minilogin && WorldConfig::get()->WorldAddress.length()==0) { _log(WORLD__LS_ERR, "**** For minilogin to work, you need to set the <address> element in the <world> section."); return false; } char errbuf[TCPConnection_ErrorBufferSize]; if ((LoginServerIP = ResolveIP(LoginServerAddress, errbuf)) == 0) { _log(WORLD__LS_ERR, "Unable to resolve '%s' to an IP.",LoginServerAddress); return false; } if (LoginServerIP == 0 || LoginServerPort == 0) { _log(WORLD__LS_ERR, "Connect info incomplete, cannot connect: %s:%d",LoginServerAddress,LoginServerPort); return false; } if (tcpc->ConnectIP(LoginServerIP, LoginServerPort, errbuf)) { _log(WORLD__LS, "Connected to Loginserver: %s:%d",LoginServerAddress,LoginServerPort); if (minilogin) SendInfo(); else SendNewInfo(); SendStatus(); zoneserver_list.SendLSZones(); return true; } else { _log(WORLD__LS_ERR, "Could not connect to login server: %s:%d %s",LoginServerAddress,LoginServerPort,errbuf); return false; } }
void ClientList::SendGuildPacket(uint32 guild_id, ServerPacket* pack) { std::set<uint32> zone_ids; LinkedListIterator<ClientListEntry*> iterator(clientlist); iterator.Reset(); while(iterator.MoreElements()) { if (iterator.GetData()->GuildID() == guild_id) { zone_ids.insert(iterator.GetData()->zone()); } iterator.Advance(); } //now we know all the zones, send it to each one... this is kinda a shitty way to do this //since its basically O(n^2) std::set<uint32>::iterator cur, end; cur = zone_ids.begin(); end = zone_ids.end(); for(; cur != end; cur++) { zoneserver_list.SendPacket(*cur, pack); } }
void ClientList::DisconnectByIP(uint32 iIP) { ClientListEntry* countCLEIPs = 0; LinkedListIterator<ClientListEntry*> iterator(clientlist); iterator.Reset(); while(iterator.MoreElements()) { countCLEIPs = iterator.GetData(); if ((countCLEIPs->GetIP() == iIP)) { if(strlen(countCLEIPs->name())) { ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer; strcpy(skp->adminname, "SessionLimit"); strcpy(skp->name, countCLEIPs->name()); skp->adminrank = 255; zoneserver_list.SendPacket(pack); safe_delete(pack); } countCLEIPs->SetOnline(CLE_Status_Offline); iterator.RemoveCurrent(); } iterator.Advance(); } }
void WorldGuildManager::ProcessZonePacket(ServerPacket *pack) { switch(pack->opcode) { case ServerOP_RefreshGuild: { if(pack->size != sizeof(ServerGuildRefresh_Struct)) { Log(Logs::Detail, Logs::Guilds, "Received ServerOP_RefreshGuild of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildRefresh_Struct)); return; } ServerGuildRefresh_Struct *s = (ServerGuildRefresh_Struct *) pack->pBuffer; Log(Logs::Detail, Logs::Guilds, "Received and broadcasting guild refresh for %d, changes: name=%d, motd=%d, rank=d, relation=%d", s->guild_id, s->name_change, s->motd_change, s->rank_change, s->relation_change); //broadcast this packet to all zones. zoneserver_list.SendPacket(pack); //preform a local refresh. if(!RefreshGuild(s->guild_id)) { Log(Logs::Detail, Logs::Guilds, "Unable to preform local refresh on guild %d", s->guild_id); //can we do anything? } break; } case ServerOP_GuildCharRefresh: { if(pack->size != sizeof(ServerGuildCharRefresh_Struct)) { Log(Logs::Detail, Logs::Guilds, "Received ServerOP_RefreshGuild of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildCharRefresh_Struct)); return; } ServerGuildCharRefresh_Struct *s = (ServerGuildCharRefresh_Struct *) pack->pBuffer; Log(Logs::Detail, Logs::Guilds, "Received and broadcasting guild member refresh for char %d to all zones with members of guild %d", s->char_id, s->guild_id); //preform the local update client_list.UpdateClientGuild(s->char_id, s->guild_id); //broadcast this update to any zone with a member in this guild. //client_list.SendGuildPacket(s->guild_id, pack); //because im sick of this not working, sending it to all zones, just spends a bit more bandwidth. zoneserver_list.SendPacket(pack); break; } case ServerOP_DeleteGuild: { if(pack->size != sizeof(ServerGuildID_Struct)) { Log(Logs::Detail, Logs::Guilds, "Received ServerOP_DeleteGuild of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildID_Struct)); return; } ServerGuildID_Struct *s = (ServerGuildID_Struct *) pack->pBuffer; Log(Logs::Detail, Logs::Guilds, "Received and broadcasting guild delete for guild %d", s->guild_id); //broadcast this packet to all zones. zoneserver_list.SendPacket(pack); //preform a local refresh. if(!LocalDeleteGuild(s->guild_id)) { Log(Logs::Detail, Logs::Guilds, "Unable to preform local delete on guild %d", s->guild_id); //can we do anything? } break; } case ServerOP_GuildMemberUpdate: { if(pack->size != sizeof(ServerGuildMemberUpdate_Struct)) { Log(Logs::Detail, Logs::Guilds, "Received ServerOP_GuildMemberUpdate of incorrect size %d, expected %d", pack->size, sizeof(ServerGuildMemberUpdate_Struct)); return; } zoneserver_list.SendPacket(pack); break; } default: Log(Logs::Detail, Logs::Guilds, "Unknown packet 0x%x received from zone??", pack->opcode); break; } }
void ClientList::SendClientVersionSummary(const char *Name) { uint32 Client62Count = 0; uint32 ClientTitaniumCount = 0; uint32 ClientSoFCount = 0; uint32 ClientSoDCount = 0; uint32 ClientUnderfootCount = 0; uint32 ClientRoFCount = 0; LinkedListIterator<ClientListEntry*> Iterator(clientlist); Iterator.Reset(); while(Iterator.MoreElements()) { ClientListEntry* CLE = Iterator.GetData(); if(CLE && CLE->zone()) { switch(CLE->GetClientVersion()) { case 1: { ++Client62Count; break; } case 2: { ++ClientTitaniumCount; break; } case 3: { ++ClientSoFCount; break; } case 4: { ++ClientSoDCount; break; } case 5: { ++ClientUnderfootCount; break; } case 6: { ++ClientRoFCount; break; } default: break; } } Iterator.Advance(); } zoneserver_list.SendEmoteMessage(Name, 0, 0, 13, "There are %i 6.2, %i Titanium, %i SoF, %i SoD, %i UF, %i RoF clients currently connected.", Client62Count, ClientTitaniumCount, ClientSoFCount, ClientSoDCount, ClientUnderfootCount, ClientRoFCount); }
void Client::Clearance(int8 response) { ZoneServer* zs = nullptr; if(instanceID > 0) { zs = zoneserver_list.FindByInstanceID(instanceID); } else { zs = zoneserver_list.FindByZoneID(zoneID); } if(zs == 0 || response == -1 || response == 0) { if (zs == 0) { clog(WORLD__CLIENT_ERR,"Unable to find zoneserver in Client::Clearance!!"); } else { clog(WORLD__CLIENT_ERR, "Invalid response %d in Client::Clearance", response); } ZoneUnavail(); return; } EQApplicationPacket* outapp; if (zs->GetCAddress() == nullptr) { clog(WORLD__CLIENT_ERR, "Unable to do zs->GetCAddress() in Client::Clearance!!"); ZoneUnavail(); return; } if (zoneID == 0) { clog(WORLD__CLIENT_ERR, "zoneID is nullptr in Client::Clearance!!"); ZoneUnavail(); return; } const char* zonename = database.GetZoneName(zoneID); if (zonename == 0) { clog(WORLD__CLIENT_ERR, "zonename is nullptr in Client::Clearance!!"); ZoneUnavail(); return; } // @bp This is the chat server /* char packetData[] = "64.37.148.34.9876,MyServer,Testchar,23cd2c95"; outapp = new EQApplicationPacket(OP_0x0282, sizeof(packetData)); strcpy((char*)outapp->pBuffer, packetData); QueuePacket(outapp); delete outapp; */ // Send zone server IP data outapp = new EQApplicationPacket(OP_ZoneServerInfo, sizeof(ZoneServerInfo_Struct)); ZoneServerInfo_Struct* zsi = (ZoneServerInfo_Struct*)outapp->pBuffer; const char *zs_addr=zs->GetCAddress(); if (!zs_addr[0]) { if (cle->IsLocalClient()) { struct in_addr in; in.s_addr = zs->GetIP(); zs_addr=inet_ntoa(in); if (!strcmp(zs_addr,"127.0.0.1")) zs_addr=WorldConfig::get()->LocalAddress.c_str(); } else { zs_addr=WorldConfig::get()->WorldAddress.c_str(); } } strcpy(zsi->ip, zs_addr); zsi->port =zs->GetCPort(); clog(WORLD__CLIENT,"Sending client to zone %s (%d:%d) at %s:%d",zonename,zoneID,instanceID,zsi->ip,zsi->port); QueuePacket(outapp); safe_delete(outapp); if (cle) cle->SetOnline(CLE_Status_Zoning); }
void ClientList::SendClientVersionSummary(const char *Name) { uint32 ClientUnusedCount = 0; uint32 ClientPCCount = 0; uint32 ClientIntelCount = 0; uint32 ClientPPCCount = 0; uint32 ClientEvolutionCount = 0; LinkedListIterator<ClientListEntry*> Iterator(clientlist); Iterator.Reset(); while(Iterator.MoreElements()) { ClientListEntry* CLE = Iterator.GetData(); if(CLE && CLE->zone()) { switch(CLE->GetClientVersion()) { case 1: { ++ClientUnusedCount; break; } case 2: { switch(CLE->GetMacClientVersion()) { case 2: { ++ClientPCCount; break; } case 4: { ++ClientIntelCount; break; } case 8: { ++ClientPPCCount; break; } } break; } case 3: { ++ClientEvolutionCount; break; } default: break; } } Iterator.Advance(); } zoneserver_list.SendEmoteMessage(Name, 0, 0, 13, "There are %i Unused, %i PC, %i Intel, %i PPC, %i Evolution clients currently connected.", ClientUnusedCount, ClientPCCount, ClientIntelCount, ClientPPCCount, ClientEvolutionCount); }
bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if (GetAccountID() == 0) { clog(WORLD__CLIENT_ERR,"Enter world with no logged in account"); eqs->Close(); return true; } if(GetAdmin() < 0) { clog(WORLD__CLIENT,"Account banned or suspended."); eqs->Close(); return true; } if (RuleI(World, MaxClientsPerIP) >= 0) { client_list.GetCLEIP(this->GetIP()); //Check current CLE Entry IPs against incoming connection } EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer; strn0cpy(char_name, ew->name, 64); EQApplicationPacket *outapp; uint32 tmpaccid = 0; charid = database.GetCharacterInfo(char_name, &tmpaccid, &zoneID, &instanceID); if (charid == 0 || tmpaccid != GetAccountID()) { clog(WORLD__CLIENT_ERR,"Could not get CharInfo for '%s'",char_name); eqs->Close(); return true; } // Make sure this account owns this character if (tmpaccid != GetAccountID()) { clog(WORLD__CLIENT_ERR,"This account does not own the character named '%s'",char_name); eqs->Close(); return true; } if(!pZoning && ew->return_home && !ew->tutorial) { CharacterSelect_Struct* cs = new CharacterSelect_Struct; memset(cs, 0, sizeof(CharacterSelect_Struct)); database.GetCharSelectInfo(GetAccountID(), cs); bool home_enabled = false; for(int x = 0; x < 10; ++x) { if(strcasecmp(cs->name[x], char_name) == 0) { if(cs->gohome[x] == 1) { home_enabled = true; break; } } } safe_delete(cs); if(home_enabled) { zoneID = database.MoveCharacterToBind(charid,4); } else { clog(WORLD__CLIENT_ERR,"'%s' is trying to go home before they're able...",char_name); database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able."); eqs->Close(); return true; } } if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) { CharacterSelect_Struct* cs = new CharacterSelect_Struct; memset(cs, 0, sizeof(CharacterSelect_Struct)); database.GetCharSelectInfo(GetAccountID(), cs); bool tutorial_enabled = false; for(int x = 0; x < 10; ++x) { if(strcasecmp(cs->name[x], char_name) == 0) { if(cs->tutorial[x] == 1) { tutorial_enabled = true; break; } } } safe_delete(cs); if(tutorial_enabled) { zoneID = RuleI(World, TutorialZoneID); database.MoveCharacterToZone(charid, database.GetZoneName(zoneID)); } else { clog(WORLD__CLIENT_ERR,"'%s' is trying to go to tutorial but are not allowed...",char_name); database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character."); eqs->Close(); return true; } } if (zoneID == 0 || !database.GetZoneName(zoneID)) { // This is to save people in an invalid zone, once it's removed from the DB database.MoveCharacterToZone(charid, "arena"); clog(WORLD__CLIENT_ERR, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zoneID, char_name); } if(instanceID > 0) { if(!database.VerifyInstanceAlive(instanceID, GetCharID())) { zoneID = database.MoveCharacterToBind(charid); instanceID = 0; } else { if(!database.VerifyZoneInstance(zoneID, instanceID)) { zoneID = database.MoveCharacterToBind(charid); instanceID = 0; } } } if(!pZoning) { database.SetGroupID(char_name, 0, charid); database.SetFirstLogon(charid, 1); if (RuleB(World, AnnounceJoinQuits) == true) //this is having an issue, its not taking a true false swap, only takes default. { zoneserver_list.SendEmoteMessage(0, 0, 0, 15, "%s is logging on!", GetCharName()); clog(WORLD__CLIENT_ERR, "Character is logging on: %s", GetCharName()); } } else{ uint32 groupid=database.GetGroupID(char_name); if(groupid>0){ char* leader=0; char leaderbuf[64]={0}; if((leader=database.GetGroupLeaderForLogin(char_name,leaderbuf)) && strlen(leader)>1){ EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer; gj->action=8; strcpy(gj->yourname,char_name); strcpy(gj->membername,leader); QueuePacket(outapp3); safe_delete(outapp3); } } } outapp = new EQApplicationPacket(OP_MOTD); char tmp[500] = {0}; if (database.GetVariable("MOTD", tmp, 500)) { outapp->size = strlen(tmp)+1; outapp->pBuffer = new uchar[outapp->size]; memset(outapp->pBuffer,0,outapp->size); strcpy((char*)outapp->pBuffer, tmp); } else { // Null Message of the Day. :) outapp->size = 1; outapp->pBuffer = new uchar[outapp->size]; outapp->pBuffer[0] = 0; } QueuePacket(outapp); safe_delete(outapp); int MailKey = MakeRandomInt(1, INT_MAX); database.SetMailKey(charid, GetIP(), MailKey); char ConnectionType; ConnectionType = 'C'; EQApplicationPacket *outapp2 = new EQApplicationPacket(OP_SetChatServer); char buffer[112]; const WorldConfig *Config = WorldConfig::get(); sprintf(buffer,"%s,%i,%s.%s,%c%08X", Config->ChatHost.c_str(), Config->ChatPort, Config->ShortName.c_str(), this->GetCharName(), ConnectionType, MailKey ); outapp2->size=strlen(buffer)+1; outapp2->pBuffer = new uchar[outapp2->size]; memcpy(outapp2->pBuffer,buffer,outapp2->size); QueuePacket(outapp2); safe_delete(outapp2); EnterWorld(); return true; }
void Client::EnterWorld(bool TryBootup) { if (zoneID == 0) return; ZoneServer* zs = nullptr; if(instanceID > 0) { if(database.VerifyInstanceAlive(instanceID, GetCharID())) { if(database.VerifyZoneInstance(zoneID, instanceID)) { zs = zoneserver_list.FindByInstanceID(instanceID); } else { instanceID = 0; zs = nullptr; database.MoveCharacterToBind(GetCharID()); ZoneUnavail(); return; } } else { instanceID = 0; zs = nullptr; database.MoveCharacterToBind(GetCharID()); ZoneUnavail(); return; } } else zs = zoneserver_list.FindByZoneID(zoneID); const char *zone_name=database.GetZoneName(zoneID, true); if (zs) { // warn the world we're comming, so it knows not to shutdown zs->IncommingClient(this); } else { if (TryBootup) { clog(WORLD__CLIENT,"Attempting autobootup of %s (%d:%d)",zone_name,zoneID,instanceID); autobootup_timeout.Start(); pwaitingforbootup = zoneserver_list.TriggerBootup(zoneID, instanceID); if (pwaitingforbootup == 0) { clog(WORLD__CLIENT_ERR,"No zoneserver available to boot up."); ZoneUnavail(); } return; } else { clog(WORLD__CLIENT_ERR,"Requested zone %s is no running.",zone_name); ZoneUnavail(); return; } } pwaitingforbootup = 0; cle->SetChar(charid, char_name); database.UpdateLiveChar(char_name, GetAccountID()); clog(WORLD__CLIENT,"%s %s (%d:%d)",seencharsel ? "Entering zone" : "Zoning to",zone_name,zoneID,instanceID); // database.SetAuthentication(account_id, char_name, zone_name, ip); if (seencharsel) { if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zoneID)) { clog(WORLD__CLIENT_ERR,"Enter world failed. Zone is locked."); ZoneUnavail(); return; } ServerPacket* pack = new ServerPacket; pack->opcode = ServerOP_AcceptWorldEntrance; pack->size = sizeof(WorldToZone_Struct); pack->pBuffer = new uchar[pack->size]; memset(pack->pBuffer, 0, pack->size); WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer; wtz->account_id = GetAccountID(); wtz->response = 0; zs->SendPacket(pack); delete pack; } else { // if they havent seen character select screen, we can assume this is a zone // to zone movement, which should be preauthorized before they leave the previous zone Clearance(1); } }
bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) { if (app->size != sizeof(LoginInfo_Struct)) { return false; } LoginInfo_Struct *li=(LoginInfo_Struct *)app->pBuffer; // Quagmire - max len for name is 18, pass 15 char name[19] = {0}; char password[16] = {0}; strn0cpy(name, (char*)li->login_info,18); strn0cpy(password, (char*)&(li->login_info[strlen(name)+1]), 15); if (strlen(password) <= 1) { // TODO: Find out how to tell the client wrong username/password clog(WORLD__CLIENT_ERR,"Login without a password"); return false; } pZoning=(li->zoning==1); #ifdef IPBASED_AUTH_HACK struct in_addr tmpip; tmpip.s_addr = ip; #endif uint32 id=0; bool minilogin = loginserverlist.MiniLogin(); if(minilogin){ struct in_addr miniip; miniip.s_addr = ip; id = database.GetMiniLoginAccount(inet_ntoa(miniip)); } else if(strncasecmp(name, "LS#", 3) == 0) id=atoi(&name[3]); else id=atoi(name); #ifdef IPBASED_AUTH_HACK if ((cle = zoneserver_list.CheckAuth(inet_ntoa(tmpip), password))) #else if (loginserverlist.Connected() == false && !pZoning) { clog(WORLD__CLIENT_ERR,"Error: Login server login while not connected to login server."); return false; } if(minilogin) client_list.CLEAdd(id, name, password, 0, ip, true); if ((minilogin && (cle = client_list.CheckAuth(id,password,ip))) || (cle = client_list.CheckAuth(id, password))) #endif { if (cle->AccountID() == 0 || (!minilogin && cle->LSID()==0)) { clog(WORLD__CLIENT_ERR,"ID is 0. Is this server connected to minilogin?"); if(!minilogin) clog(WORLD__CLIENT_ERR,"If so you forget the minilogin variable..."); else clog(WORLD__CLIENT_ERR,"Could not find a minilogin account, verify ip address logging into minilogin is the same that is in your account table."); return false; } cle->SetOnline(); clog(WORLD__CLIENT,"Logged in. Mode=%s",pZoning ? "(Zoning)" : "(CharSel)"); if(minilogin){ WorldConfig::DisableStats(); clog(WORLD__CLIENT,"MiniLogin Account #%d",cle->AccountID()); } else { clog(WORLD__CLIENT,"LS Account #%d",cle->LSID()); } const WorldConfig *Config=WorldConfig::get(); if(Config->UpdateStats){ ServerPacket* pack = new ServerPacket; pack->opcode = ServerOP_LSPlayerJoinWorld; pack->size = sizeof(ServerLSPlayerJoinWorld_Struct); pack->pBuffer = new uchar[pack->size]; memset(pack->pBuffer,0,pack->size); ServerLSPlayerJoinWorld_Struct* join =(ServerLSPlayerJoinWorld_Struct*)pack->pBuffer; strcpy(join->key,GetLSKey()); join->lsaccount_id = GetLSID(); loginserverlist.SendPacket(pack); safe_delete(pack); } expansion = database.GetExpansion(cle->AccountID()); if(ClientVersionBit == 1) { SendApproveWorld(); SendEnterWorld(cle->name()); SendExpansionInfo(); SendCharInfo(); } else { if (!pZoning && ClientVersionBit != 0) SendGuildList(); SendLogServer(); SendApproveWorld(); SendEnterWorld(cle->name()); if (!pZoning) { SendExpansionInfo(); SendCharInfo(); database.LoginIP(cle->AccountID(), long2ip(GetIP()).c_str()); } } } else { // TODO: Find out how to tell the client wrong username/password clog(WORLD__CLIENT_ERR,"Bad/Expired session key '%s'",name); return false; } if (!cle) return true; cle->SetIP(GetIP()); return true; }
bool LoginServer::Process() { const WorldConfig *Config=WorldConfig::get(); if (statusupdate_timer.Check()) { this->SendStatus(); } /************ Get all packets from packet manager out queue and process them ************/ ServerPacket *pack = 0; while((pack = tcpc->PopPacket())) { _log(WORLD__LS_TRACE,"Recevied ServerPacket from LS OpCode 0x04x",pack->opcode); _hex(WORLD__LS_TRACE,pack->pBuffer,pack->size); switch(pack->opcode) { case 0: break; case ServerOP_KeepAlive: { // ignore this break; } case ServerOP_UsertoWorldReq: { UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer; uint32 id = database.GetAccountIDFromLSID(utwr->lsaccountid); int16 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; } int32 x = Config->MaxClients; if( (int32)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; SendPacket(outpack); delete outpack; break; } case ServerOP_LSClientAuth: { ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack->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 (pack->size > 1) { _log(WORLD__LS_ERR, " %s",pack->pBuffer); } break; } case ServerOP_SystemwideMessage: { ServerSystemwideMessage* swm = (ServerSystemwideMessage*) pack->pBuffer; zoneserver_list.SendEmoteMessageRaw(0, 0, 0, swm->type, swm->message); break; } case ServerOP_LSRemoteAddr: { if (!Config->WorldAddress.length()) { WorldConfig::SetWorldAddress((char *)pack->pBuffer); _log(WORLD__LS, "Loginserver provided %s as world address",pack->pBuffer); } break; } case ServerOP_LSAccountUpdate: { _log(WORLD__LS, "Received ServerOP_LSAccountUpdate packet from loginserver"); CanAccountUpdate = true; break; } default: { _log(WORLD__LS_ERR, "Unknown LSOpCode: 0x%04x size=%d",(int)pack->opcode,pack->size); DumpPacket(pack->pBuffer, pack->size); break; } } delete pack; } return true; }
int main(int argc, char** argv) { // Load server configuration _log(WORLD__INIT, "Loading server configuration.."); if (!WorldConfig::LoadConfig()) { _log(WORLD__INIT_ERR, "Loading server configuration failed."); return(1); } const WorldConfig *Config=WorldConfig::get(); if(!load_log_settings(Config->LogSettingsFile.c_str())) _log(WORLD__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str()); else _log(WORLD__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str()); _log(WORLD__INIT, "CURRENT_WORLD_VERSION:%s", CURRENT_WORLD_VERSION); #ifdef _DEBUG _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif if (signal(SIGINT, CatchSignal) == SIG_ERR) { _log(WORLD__INIT_ERR, "Could not set signal handler"); return 0; } if (signal(SIGTERM, CatchSignal) == SIG_ERR) { _log(WORLD__INIT_ERR, "Could not set signal handler"); return 0; } #ifndef WIN32 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { _log(WORLD__INIT_ERR, "Could not set signal handler"); return 0; } #endif _log(WORLD__INIT, "Connecting to MySQL..."); if (!database.Connect( Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(), Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) { _log(WORLD__INIT_ERR, "Cannot continue without a database connection."); return(1); } dbasync = new DBAsync(&database); guild_mgr.SetDatabase(&database); if (argc >= 2) { char tmp[2]; if (strcasecmp(argv[1], "help") == 0 || strcasecmp(argv[1], "?") == 0 || strcasecmp(argv[1], "/?") == 0 || strcasecmp(argv[1], "-?") == 0 || strcasecmp(argv[1], "-h") == 0 || strcasecmp(argv[1], "-help") == 0) { cout << "Worldserver command line commands:" << endl; cout << "adduser username password flag - adds a user account" << endl; cout << "flag username flag - sets GM flag on the account" << endl; cout << "startzone zoneshortname - sets the starting zone" << endl; cout << "-holdzones - reboots lost zones" << endl; return 0; } else if (strcasecmp(argv[1], "-holdzones") == 0) { cout << "Reboot Zones mode ON" << endl; holdzones = true; } else if (database.GetVariable("disablecommandline", tmp, 2)) { if (strlen(tmp) == 1) { if (tmp[0] == '1') { cout << "Command line disabled in database... exiting" << endl; return 0; } } } else if (strcasecmp(argv[1], "adduser") == 0) { if (argc == 5) { if (Seperator::IsNumber(argv[4])) { if (atoi(argv[4]) >= 0 && atoi(argv[4]) <= 255) { if (database.CreateAccount(argv[2], argv[3], atoi(argv[4])) == 0) cout << "database.CreateAccount failed." << endl; else cout << "Account created: Username='******', Password='******', status=" << argv[4] << endl; return 0; } } } cout << "Usage: world adduser username password flag" << endl; cout << "flag = 0, 1 or 2" << endl; return 0; } else if (strcasecmp(argv[1], "flag") == 0) { if (argc == 4) { if (Seperator::IsNumber(argv[3])) { if (atoi(argv[3]) >= 0 && atoi(argv[3]) <= 255) { if (database.SetAccountStatus(argv[2], atoi(argv[3]))) cout << "Account flagged: Username='******', status=" << argv[3] << endl; else cout << "database.SetAccountStatus failed." << endl; return 0; } } } cout << "Usage: world flag username flag" << endl; cout << "flag = 0-200" << endl; return 0; } else if (strcasecmp(argv[1], "startzone") == 0) { if (argc == 3) { if (strlen(argv[2]) < 3) { cout << "Error: zone name too short" << endl; } else if (strlen(argv[2]) > 15) { cout << "Error: zone name too long" << endl; } else { if (database.SetVariable("startzone", argv[2])) cout << "Starting zone changed: '" << argv[2] << "'" << endl; else cout << "database.SetVariable failed." << endl; } return 0; } cout << "Usage: world startzone zoneshortname" << endl; return 0; } else { cout << "Error, unknown command line option" << endl; return 0; } } srand(time(NULL)); if(Config->WorldHTTPEnabled) { _log(WORLD__INIT, "Starting HTTP world service..."); http_server.Start(Config->WorldHTTPPort, Config->WorldHTTPMimeFile.c_str()); } else { _log(WORLD__INIT, "HTTP world service disabled."); } _log(WORLD__INIT, "Loading variables.."); database.LoadVariables(); _log(WORLD__INIT, "Loading zones.."); database.LoadZoneNames(); _log(WORLD__INIT, "Clearing groups.."); database.ClearGroup(); _log(WORLD__INIT, "Clearing raids.."); database.ClearRaid(); database.ClearRaidDetails(); _log(WORLD__INIT, "Loading items.."); if (!database.LoadItems()) { _log(WORLD__INIT_ERR, "Error: Could not load item data. But ignoring"); } _log(WORLD__INIT, "Loading guilds.."); guild_mgr.LoadGuilds(); //rules: { char tmp[64]; if (database.GetVariable("RuleSet", tmp, sizeof(tmp)-1)) { _log(WORLD__INIT, "Loading rule set '%s'", tmp); if(!rules->LoadRules(&database, tmp)) { _log(WORLD__INIT_ERR, "Failed to load ruleset '%s', falling back to defaults.", tmp); } } else { if(!rules->LoadRules(&database, "default")) { _log(WORLD__INIT, "No rule set configured, using default rules"); } else { _log(WORLD__INIT, "Loaded default rule set 'default'", tmp); } } } if(RuleB(World, ClearTempMerchantlist)){ _log(WORLD__INIT, "Clearing temporary merchant lists.."); database.ClearMerchantTemp(); } _log(WORLD__INIT, "Loading EQ time of day.."); if (!zoneserver_list.worldclock.loadFile(Config->EQTimeFile.c_str())) _log(WORLD__INIT_ERR, "Unable to load %s", Config->EQTimeFile.c_str()); _log(WORLD__INIT, "Loading launcher list.."); launcher_list.LoadList(); char tmp[20]; tmp[0] = '\0'; database.GetVariable("holdzones",tmp, 20); if ((strcasecmp(tmp, "1") == 0)) { holdzones = true; } _log(WORLD__INIT, "Reboot zone modes %s",holdzones ? "ON" : "OFF"); _log(WORLD__INIT, "Deleted %i stale player corpses from database", database.DeleteStalePlayerCorpses()); _log(WORLD__INIT, "Deleted %i stale player backups from database", database.DeleteStalePlayerBackups()); _log(WORLD__INIT, "Purging expired instances"); database.PurgeExpiredInstances(); Timer PurgeInstanceTimer(450000); PurgeInstanceTimer.Start(450000); char errbuf[TCPConnection_ErrorBufferSize]; if (tcps.Open(Config->WorldTCPPort, errbuf)) { _log(WORLD__INIT,"Zone (TCP) listener started."); } else { _log(WORLD__INIT_ERR,"Failed to start zone (TCP) listener on port %d:",Config->WorldTCPPort); _log(WORLD__INIT_ERR," %s",errbuf); return 1; } if (eqsf.Open()) { _log(WORLD__INIT,"Client (UDP) listener started."); } else { _log(WORLD__INIT_ERR,"Failed to start client (UDP) listener (port 9000)"); return 1; } //ItemInst a((SharedDatabase *)&database,(uint32)17354,0); //ItemInst b((SharedDatabase *)&database,(uint32)26885,0); //ItemInst c((SharedDatabase *)&database,(uint32)41075,0); //ItemInst d((SharedDatabase *)&database,(uint32)29041,0); //d.PutAugment(&database,0,41006); //a.PutItem(0,b); //a.PutItem(1,c); //a.PutItem(2,d); //_log(WORLD__INIT,"%s\n",Client62::SerializeItem(&a,30,0)); //register all the patches we have avaliable with the stream identifier. EQStreamIdentifier stream_identifier; RegisterAllPatches(stream_identifier); zoneserver_list.shutdowntimer=new Timer(60000); zoneserver_list.shutdowntimer->Disable(); zoneserver_list.reminder = new Timer(20000); zoneserver_list.reminder->Disable(); Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect InterserverTimer.Trigger(); EQStream* eqs; EmuTCPConnection* tcpc; EQStreamInterface *eqsi; while(RunLoops) { Timer::SetCurrentTime(); //check the factory for any new incoming streams. while ((eqs = eqsf.Pop())) { //pull the stream out of the factory and give it to the stream identifier //which will figure out what patch they are running, and set up the dynamic //structures and opcodes for that patch. struct in_addr in; in.s_addr = eqs->GetRemoteIP(); _log(WORLD__CLIENT, "New connection from %s:%d", inet_ntoa(in),ntohs(eqs->GetRemotePort())); stream_identifier.AddStream(eqs); //takes the stream } //give the stream identifier a chance to do its work.... stream_identifier.Process(); //check the stream identifier for any now-identified streams while((eqsi = stream_identifier.PopIdentified())) { //now that we know what patch they are running, start up their client object struct in_addr in; in.s_addr = eqsi->GetRemoteIP(); if (RuleB(World, UseBannedIPsTable)){ //Lieka: Check to see if we have the responsibility for blocking IPs. _log(WORLD__CLIENT, "Checking inbound connection %s against BannedIPs table", inet_ntoa(in)); if (!database.CheckBannedIPs(inet_ntoa(in))){ //Lieka: Check inbound IP against banned IP table. _log(WORLD__CLIENT, "Connection %s PASSED banned IPs check. Processing connection.", inet_ntoa(in)); Client* client = new Client(eqsi); // @merth: client->zoneattempt=0; client_list.Add(client); } else { _log(WORLD__CLIENT, "Connection from %s FAILED banned IPs check. Closing connection.", inet_ntoa(in)); eqsi->Close(); //Lieka: If the inbound IP is on the banned table, close the EQStream. } } if (!RuleB(World, UseBannedIPsTable)){ _log(WORLD__CLIENT, "New connection from %s:%d, processing connection", inet_ntoa(in), ntohs(eqsi->GetRemotePort())); Client* client = new Client(eqsi); // @merth: client->zoneattempt=0; client_list.Add(client); } } client_list.Process(); while ((tcpc = tcps.NewQueuePop())) { struct in_addr in; in.s_addr = tcpc->GetrIP(); _log(WORLD__ZONE, "New TCP connection from %s:%d", inet_ntoa(in),tcpc->GetrPort()); console_list.Add(new Console(tcpc)); } if(PurgeInstanceTimer.Check()) { database.PurgeExpiredInstances(); } //check for timeouts in other threads timeout_manager.CheckTimeouts(); loginserver.Process(); console_list.Process(); zoneserver_list.Process(); launcher_list.Process(); LFPGroupList.Process(); if (InterserverTimer.Check()) { InterserverTimer.Start(); database.ping(); AsyncLoadVariables(dbasync, &database); if (Config->LoginHost.length() && loginserver.Connected() == false) { #ifdef WIN32 _beginthread(AutoInitLoginServer, 0, NULL); #else pthread_t thread; pthread_create(&thread, NULL, &AutoInitLoginServer, NULL); #endif } } if (numclients == 0) { Sleep(50); continue; } Sleep(20); } _log(WORLD__SHUTDOWN,"World main loop completed."); _log(WORLD__SHUTDOWN,"Shutting down console connections (if any)."); console_list.KillAll(); _log(WORLD__SHUTDOWN,"Shutting down zone connections (if any)."); zoneserver_list.KillAll(); _log(WORLD__SHUTDOWN,"Zone (TCP) listener stopped."); tcps.Close(); _log(WORLD__SHUTDOWN,"Client (UDP) listener stopped."); eqsf.Close(); _log(WORLD__SHUTDOWN,"Signaling HTTP service to stop..."); http_server.Stop(); #if 0 #if defined(SHAREMEM) && !defined(WIN32) for (int ipc_files = 0; ipc_files <= 4; ipc_files++) { key_t share_key; switch (ipc_files) { // Item case 0: share_key = ftok(".", 'I'); break; // Npctype case 1: share_key = ftok(".", 'N'); break; // Door case 2: share_key = ftok(".", 'D'); break; // Spell case 3: share_key = ftok(".", 'S'); break; // Faction case 4: share_key = ftok(".", 'F'); break; // ERROR Fatal default: cerr<<"Opps!"<<endl; share_key = 0xFF; break; } int share_id = shmget(share_key, 0, IPC_NOWAIT|0400); if (share_id <= 0) { cerr<<"exiting could not check user count on shared memory ipcs mem leak!!!!!!!! id="<<share_id<<" key:"<<share_key<<endl; exit(1); } struct shmid_ds mem_users; if ((shmctl(share_id, IPC_STAT, &mem_users)) != 0) { cerr<<"exiting error checking user count on shared memory, marking for deletion!!!!!id="<<share_id<<" key:"<<share_key<<endl; shmctl(share_id, IPC_RMID, 0); exit(1); } if (mem_users.shm_nattch == 0) { //cerr<<"exiting stale share marked for deletion!id="<<share_id<<" key:"<<share_key<<endl; shmctl(share_id, IPC_RMID, 0); } else if (mem_users.shm_nattch == 1) { //cerr<<"mem_users = 1"<<endl; // Detatch and delete shared mem here EMuShareMemDLL.Unload(); shmctl(share_id, IPC_RMID, 0); } } #endif #endif CheckEQEMuErrorAndPause(); return 0; }
int EQW::CountZones() { return(zoneserver_list.GetZoneCount()); }
int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformWorld); set_exception_handler(); // Load server configuration _log(WORLD__INIT, "Loading server configuration.."); if (!WorldConfig::LoadConfig()) { _log(WORLD__INIT_ERR, "Loading server configuration failed."); return(1); } const WorldConfig *Config=WorldConfig::get(); if(!load_log_settings(Config->LogSettingsFile.c_str())) _log(WORLD__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str()); else _log(WORLD__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str()); _log(WORLD__INIT, "CURRENT_VERSION: %s", CURRENT_VERSION); #ifdef _DEBUG _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif if (signal(SIGINT, CatchSignal) == SIG_ERR) { _log(WORLD__INIT_ERR, "Could not set signal handler"); return 0; } if (signal(SIGTERM, CatchSignal) == SIG_ERR) { _log(WORLD__INIT_ERR, "Could not set signal handler"); return 0; } #ifndef WIN32 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { _log(WORLD__INIT_ERR, "Could not set signal handler"); return 0; } #endif // add login server config to list if (Config->LoginCount == 0) { if (Config->LoginHost.length()) { loginserverlist.Add(Config->LoginHost.c_str(), Config->LoginPort, Config->LoginAccount.c_str(), Config->LoginPassword.c_str()); _log(WORLD__INIT, "Added loginserver %s:%i", Config->LoginHost.c_str(), Config->LoginPort); } } else { LinkedList<LoginConfig*> loginlist=Config->loginlist; LinkedListIterator<LoginConfig*> iterator(loginlist); iterator.Reset(); while(iterator.MoreElements()) { loginserverlist.Add(iterator.GetData()->LoginHost.c_str(), iterator.GetData()->LoginPort, iterator.GetData()->LoginAccount.c_str(), iterator.GetData()->LoginPassword.c_str()); _log(WORLD__INIT, "Added loginserver %s:%i", iterator.GetData()->LoginHost.c_str(), iterator.GetData()->LoginPort); iterator.Advance(); } } _log(WORLD__INIT, "Connecting to MySQL..."); if (!database.Connect( Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(), Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) { _log(WORLD__INIT_ERR, "Cannot continue without a database connection."); return(1); } dbasync = new DBAsync(&database); guild_mgr.SetDatabase(&database); if (argc >= 2) { char tmp[2]; if (strcasecmp(argv[1], "help") == 0 || strcasecmp(argv[1], "?") == 0 || strcasecmp(argv[1], "/?") == 0 || strcasecmp(argv[1], "-?") == 0 || strcasecmp(argv[1], "-h") == 0 || strcasecmp(argv[1], "-help") == 0) { cout << "Worldserver command line commands:" << endl; cout << "adduser username password flag - adds a user account" << endl; cout << "flag username flag - sets GM flag on the account" << endl; cout << "startzone zoneshortname - sets the starting zone" << endl; cout << "-holdzones - reboots lost zones" << endl; return 0; } else if (strcasecmp(argv[1], "-holdzones") == 0) { cout << "Reboot Zones mode ON" << endl; holdzones = true; } else if (database.GetVariable("disablecommandline", tmp, 2)) { if (strlen(tmp) == 1) { if (tmp[0] == '1') { cout << "Command line disabled in database... exiting" << endl; return 0; } } } else if (strcasecmp(argv[1], "adduser") == 0) { if (argc == 5) { if (Seperator::IsNumber(argv[4])) { if (atoi(argv[4]) >= 0 && atoi(argv[4]) <= 255) { if (database.CreateAccount(argv[2], argv[3], atoi(argv[4])) == 0) cout << "database.CreateAccount failed." << endl; else cout << "Account created: Username='******', Password='******', status=" << argv[4] << endl; return 0; } } } cout << "Usage: world adduser username password flag" << endl; cout << "flag = 0, 1 or 2" << endl; return 0; } else if (strcasecmp(argv[1], "flag") == 0) { if (argc == 4) { if (Seperator::IsNumber(argv[3])) { if (atoi(argv[3]) >= 0 && atoi(argv[3]) <= 255) { if (database.SetAccountStatus(argv[2], atoi(argv[3]))) cout << "Account flagged: Username='******', status=" << argv[3] << endl; else cout << "database.SetAccountStatus failed." << endl; return 0; } } } cout << "Usage: world flag username flag" << endl; cout << "flag = 0-200" << endl; return 0; } else if (strcasecmp(argv[1], "startzone") == 0) { if (argc == 3) { if (strlen(argv[2]) < 3) { cout << "Error: zone name too short" << endl; } else if (strlen(argv[2]) > 15) { cout << "Error: zone name too long" << endl; } else { if (database.SetVariable("startzone", argv[2])) cout << "Starting zone changed: '" << argv[2] << "'" << endl; else cout << "database.SetVariable failed." << endl; } return 0; } cout << "Usage: world startzone zoneshortname" << endl; return 0; } else { cout << "Error, unknown command line option" << endl; return 0; } } if(Config->WorldHTTPEnabled) { _log(WORLD__INIT, "Starting HTTP world service..."); http_server.Start(Config->WorldHTTPPort, Config->WorldHTTPMimeFile.c_str()); } else { _log(WORLD__INIT, "HTTP world service disabled."); } _log(WORLD__INIT, "Loading variables.."); database.LoadVariables(); _log(WORLD__INIT, "Loading zones.."); database.LoadZoneNames(); _log(WORLD__INIT, "Clearing groups.."); database.ClearGroup(); _log(WORLD__INIT, "Clearing raids.."); database.ClearRaid(); database.ClearRaidDetails(); _log(WORLD__INIT, "Loading items.."); if (!database.LoadItems()) { _log(WORLD__INIT_ERR, "Error: Could not load item data. But ignoring"); } _log(WORLD__INIT, "Loading guilds.."); guild_mgr.LoadGuilds(); //rules: { char tmp[64]; if (database.GetVariable("RuleSet", tmp, sizeof(tmp)-1)) { _log(WORLD__INIT, "Loading rule set '%s'", tmp); if(!RuleManager::Instance()->LoadRules(&database, tmp)) { _log(WORLD__INIT_ERR, "Failed to load ruleset '%s', falling back to defaults.", tmp); } } else { if(!RuleManager::Instance()->LoadRules(&database, "default")) { _log(WORLD__INIT, "No rule set configured, using default rules"); } else { _log(WORLD__INIT, "Loaded default rule set 'default'", tmp); } } } if(RuleB(World, ClearTempMerchantlist)){ _log(WORLD__INIT, "Clearing temporary merchant lists.."); database.ClearMerchantTemp(); } _log(WORLD__INIT, "Loading EQ time of day.."); if (!zoneserver_list.worldclock.loadFile(Config->EQTimeFile.c_str())) _log(WORLD__INIT_ERR, "Unable to load %s", Config->EQTimeFile.c_str()); _log(WORLD__INIT, "Loading launcher list.."); launcher_list.LoadList(); char tmp[20]; tmp[0] = '\0'; database.GetVariable("holdzones",tmp, 20); if ((strcasecmp(tmp, "1") == 0)) { holdzones = true; } _log(WORLD__INIT, "Reboot zone modes %s",holdzones ? "ON" : "OFF"); _log(WORLD__INIT, "Deleted %i stale player corpses from database", database.DeleteStalePlayerCorpses()); if (RuleB(World, DeleteStaleCorpeBackups) == true) { _log(WORLD__INIT, "Deleted %i stale player backups from database", database.DeleteStalePlayerBackups()); } _log(WORLD__INIT, "Loading adventures..."); if(!adventure_manager.LoadAdventureTemplates()) { _log(WORLD__INIT_ERR, "Unable to load adventure templates."); } if(!adventure_manager.LoadAdventureEntries()) { _log(WORLD__INIT_ERR, "Unable to load adventure templates."); } adventure_manager.Load(); adventure_manager.LoadLeaderboardInfo(); _log(WORLD__INIT, "Purging expired instances"); database.PurgeExpiredInstances(); Timer PurgeInstanceTimer(450000); PurgeInstanceTimer.Start(450000); _log(WORLD__INIT, "Loading char create info..."); database.LoadCharacterCreateAllocations(); database.LoadCharacterCreateCombos(); char errbuf[TCPConnection_ErrorBufferSize]; if (tcps.Open(Config->WorldTCPPort, errbuf)) { _log(WORLD__INIT,"Zone (TCP) listener started."); } else { _log(WORLD__INIT_ERR,"Failed to start zone (TCP) listener on port %d:",Config->WorldTCPPort); _log(WORLD__INIT_ERR," %s",errbuf); return 1; } if (eqsf.Open()) { _log(WORLD__INIT,"Client (UDP) listener started."); } else { _log(WORLD__INIT_ERR,"Failed to start client (UDP) listener (port 9000)"); return 1; } //register all the patches we have avaliable with the stream identifier. EQStreamIdentifier stream_identifier; RegisterAllPatches(stream_identifier); zoneserver_list.shutdowntimer = new Timer(60000); zoneserver_list.shutdowntimer->Disable(); zoneserver_list.reminder = new Timer(20000); zoneserver_list.reminder->Disable(); Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect InterserverTimer.Trigger(); uint8 ReconnectCounter = 100; EQStream* eqs; EmuTCPConnection* tcpc; EQStreamInterface *eqsi; while(RunLoops) { Timer::SetCurrentTime(); //check the factory for any new incoming streams. while ((eqs = eqsf.Pop())) { //pull the stream out of the factory and give it to the stream identifier //which will figure out what patch they are running, and set up the dynamic //structures and opcodes for that patch. struct in_addr in; in.s_addr = eqs->GetRemoteIP(); _log(WORLD__CLIENT, "New connection from %s:%d", inet_ntoa(in),ntohs(eqs->GetRemotePort())); stream_identifier.AddStream(eqs); //takes the stream } //give the stream identifier a chance to do its work.... stream_identifier.Process(); //check the stream identifier for any now-identified streams while((eqsi = stream_identifier.PopIdentified())) { //now that we know what patch they are running, start up their client object struct in_addr in; in.s_addr = eqsi->GetRemoteIP(); if (RuleB(World, UseBannedIPsTable)){ //Lieka: Check to see if we have the responsibility for blocking IPs. _log(WORLD__CLIENT, "Checking inbound connection %s against BannedIPs table", inet_ntoa(in)); if (!database.CheckBannedIPs(inet_ntoa(in))){ //Lieka: Check inbound IP against banned IP table. _log(WORLD__CLIENT, "Connection %s PASSED banned IPs check. Processing connection.", inet_ntoa(in)); Client* client = new Client(eqsi); // @merth: client->zoneattempt=0; client_list.Add(client); } else { _log(WORLD__CLIENT, "Connection from %s FAILED banned IPs check. Closing connection.", inet_ntoa(in)); eqsi->Close(); //Lieka: If the inbound IP is on the banned table, close the EQStream. } } if (!RuleB(World, UseBannedIPsTable)){ _log(WORLD__CLIENT, "New connection from %s:%d, processing connection", inet_ntoa(in), ntohs(eqsi->GetRemotePort())); Client* client = new Client(eqsi); // @merth: client->zoneattempt=0; client_list.Add(client); } } client_list.Process(); while ((tcpc = tcps.NewQueuePop())) { struct in_addr in; in.s_addr = tcpc->GetrIP(); _log(WORLD__ZONE, "New TCP connection from %s:%d", inet_ntoa(in),tcpc->GetrPort()); console_list.Add(new Console(tcpc)); } if(PurgeInstanceTimer.Check()) { database.PurgeExpiredInstances(); } //check for timeouts in other threads timeout_manager.CheckTimeouts(); loginserverlist.Process(); console_list.Process(); zoneserver_list.Process(); launcher_list.Process(); UCSLink.Process(); QSLink.Process(); LFPGroupList.Process(); adventure_manager.Process(); if (InterserverTimer.Check()) { InterserverTimer.Start(); database.ping(); AsyncLoadVariables(dbasync, &database); ReconnectCounter++; if (ReconnectCounter >= 12) { // only create thread to reconnect every 10 minutes. previously we were creating a new thread every 10 seconds ReconnectCounter = 0; if (loginserverlist.AllConnected() == false) { #ifdef _WINDOWS _beginthread(AutoInitLoginServer, 0, nullptr); #else pthread_t thread; pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr); #endif } } } if (numclients == 0) { Sleep(50); continue; } Sleep(20); } _log(WORLD__SHUTDOWN,"World main loop completed."); _log(WORLD__SHUTDOWN,"Shutting down console connections (if any)."); console_list.KillAll(); _log(WORLD__SHUTDOWN,"Shutting down zone connections (if any)."); zoneserver_list.KillAll(); _log(WORLD__SHUTDOWN,"Zone (TCP) listener stopped."); tcps.Close(); _log(WORLD__SHUTDOWN,"Client (UDP) listener stopped."); eqsf.Close(); _log(WORLD__SHUTDOWN,"Signaling HTTP service to stop..."); http_server.Stop(); CheckEQEMuErrorAndPause(); return 0; }