protected override GameServerInfo<OutboundServerConnection> GetServerInfo(string serverName) { GameServerInfo<OutboundServerConnection> gsi = null; string serverType = ""; string address = ""; int port = -1; int curConnections = -1; int maxConnections = -1; // Grab all registered content servers. if (DB.Instance.Server_GetRegistrations(serverName, out serverType, out address, out port, out curConnections, out maxConnections)) { gsi = new GameServerInfo<OutboundServerConnection>(); gsi.Name = serverName; gsi.IP = address; gsi.Port = port; gsi.CurUsers = curConnections; gsi.MaxUsers = maxConnections; if (gsi.CurUsers >= gsi.MaxUsers) { return null; } } return gsi; }
protected override GameServerInfo <OutboundServerConnection> GetTargetServerForClusterHandoff(string serverGroup) { GameServerInfo <OutboundServerConnection> gsi = null; List <string> addresses; List <string> ids; List <int> ports; List <int> curConnections; List <int> maxConnections; // Grab all registered content servers. if (DB.Instance.Server_GetRegistrations("", "chat", out addresses, out ids, out ports, out curConnections, out maxConnections)) { // find the lowest population server int low = 0; float lowRatio = 1f; for (int i = 0; i < ids.Count; i++) { float ratio = (float)curConnections[i] / (float)maxConnections[i]; if (ratio < lowRatio) { lowRatio = ratio; low = i; } } if (lowRatio >= 1) { // All servers are at capacity. return(null); } // Create a temp object with latest info from DB gsi = new GameServerInfo <OutboundServerConnection>(); gsi.UserID = ids[low]; gsi.Name = ids[low]; gsi.IP = addresses[low]; gsi.Port = ports[low]; gsi.CurUsers = curConnections[low]; gsi.MaxUsers = maxConnections[low]; } return(gsi); }
/// <summary> /// Queries the hive to see which lobby (central) server we can bounce the player to. /// Returns false if all lobby servers claim to be at capacity. At that point, just D/C the player. /// </summary> /// <param name="address"></param> /// <param name="port"></param> /// <returns></returns> public static bool GetCentralHandoffAddress(ref string address, ref int port, ref string targetId) { GameServerInfo <OutboundServerConnection> gsi = null; // Grab the game server with the least number of players List <string> addresses; List <string> ids; List <int> ports; List <int> curConnections; List <int> maxConnections; int low = -1; if (!DB.Instance.Server_GetRegistrations("lobby", out addresses, out ids, out ports, out curConnections, out maxConnections)) { // no lobby servers available return(false); } else { low = 0; float lowRatio = 1f; for (int i = 0; i < ids.Count; i++) { float ratio = (float)curConnections[i] / (float)maxConnections[i]; if (ratio < lowRatio) { lowRatio = ratio; low = i; } } if (lowRatio >= 1) { // All servers are at capacity return(false); } } address = addresses[low]; port = ports[low]; targetId = ids[low]; return(true); }
private void OnCreateNewGame(INetworkConnection con, Packet gmsg) { PacketGenericMessage genMsg = gmsg as PacketGenericMessage; PacketMatchNotification note = (PacketMatchNotification)CreatePacket((int)LobbyPacketType.MatchNotification, 0, false, false); note.Kind = MatchNotificationType.MatchCreated; note.NeedsReply = false; if (!ValidateHasCurrentCharacter()) { genMsg.ReplyPacket = note; note.ReplyMessage = "You must select a character before you can create a new game."; note.ReplyCode = ReplyType.Failure; return; } // // <h2 style="text-align: center"><span style="color: #993300;"><a href="http://www.survivalnotes.org/content/category/fire"><span style="color: #993300;">Latest Entries</span></a> <a href="http://www.survivalnotes.org/content/category/fire?r_sortby=highest_rated&r_orderby=desc"><span style="color: #993300;">Highest Rated Entries</span></a></span></h2> // <h2 style="text-align: center"><span style="color: #993300;"><a href="http://www.survivalnotes.org/content/category/fire"><span style="color: #993300;">Latest Entries</span></a> <a href="http://www.survivalnotes.org/content/category/fire?r_sortby=highest_rated&r_orderby=desc"><span style="color: #993300;">Highest Rated Entries</span></a></span></h2> // Log1.Logger(MyServer.ServerUserID).Info(string.Format("Player {0} requesting create new game '{1}' ...", ServerUser.AccountName, genMsg.Parms.GetStringProperty((int)PropertyID.Name))); string msg = ""; GameServerInfo <OutboundServerConnection> gsi = RequestCreateNewGameServer(out msg); genMsg.ReplyPacket = note; note.ReplyMessage = msg; if (gsi == null) { // Failed. Either no servers online, or they are full. note.ReplyCode = ReplyType.Failure; return; } else { // Contact that server and request a game be created. note.ReplyCode = ReplyType.OK; ServerUser.TransferToServerUnassisted(gsi.IP, gsi.Port, Guid.Empty, gsi.Name, gsi.UserID); } }
/// <summary> /// Phase 2: Player requests to play on a specified game server. This method forwards that request to the game server. /// </summary> private void OnClusterHandoffRequest(INetworkConnection con, Packet msg) { PacketRequestHandoffToServerCluster packetRequestHandoffToServer = msg as PacketRequestHandoffToServerCluster; if (!ServerUser.IsAuthenticated) { KillConnection(" [" + ServerUser.AccountName + "] requested server hand off to [" + packetRequestHandoffToServer.TargetServerName + "] without being authenticated."); } GameServerInfo <OutboundServerConnection> gsi = GetServerInfo(packetRequestHandoffToServer.TargetServerName); if (gsi == null) // cluster offline or at capacity? { PacketGameServerTransferResult p = (PacketGameServerTransferResult)CreatePacket((int)PacketType.PacketGameServerAccessGranted, 0, true, true); p.ReplyMessage = "Game service not currently available."; p.ReplyCode = ReplyType.Failure; // send an updated listing of online servers string servers = ""; foreach (GameServerInfoGroup gr in MyServer.OutboundServerGroups.Groups.Values) { string serverInfo = gr.ID + "," + gr.HasLiveOutboundServerConnections; servers += "|" + serverInfo; } servers = servers.Trim('|'); p.Parms.SetProperty((int)PropertyID.ServerListing, servers); msg.ReplyPacket = p; return; } Log1.Logger("LoginServer.Inbound.Login").Info("Player " + ServerUser.AccountName + " is requesting handoff to game server " + gsi.Name); // request auth ticket from game server Log1.Logger("LoginServer.Inbound.Login").Debug("Requesting authenticated client *" + ServerUser.AccountName + "* (" + RemoteIP + ") to be handed off to server group " + packetRequestHandoffToServer.TargetServerName + "."); ServerUser.TransferToServerUnassisted(gsi.IP, gsi.Port, Guid.Empty, gsi.UserID, gsi.Name); //gsi.Connection.RequestPlayerHandoff(ServerUser.ID, ServerUser.AccountName, packetRequestHandoffToServer.TargetResource, ServerUser.Profile, null, ""); }
protected override PacketLoginResult CreateLoginResultPacket() { PacketLoginResult lr = (PacketLoginResult)CreatePacket((int)PacketType.LoginResult, 0, true, true); lr.ReplyCode = ReplyType.OK; GameServerInfo <OutboundServerConnection> cons = GetTargetServerForClusterHandoff(""); bool haveAnyOnline = cons != null; if (cons != null) { lr.ReplyMessage = cons.Name + "," + "TRUE|"; } if (!haveAnyOnline) { lr.ReplyMessage = "No servers available for service. Try again later."; lr.IsCritical = true; lr.ReplyCode = ReplyType.Failure; } Log1.Logger("LoginServer.Inbound.Login").Debug("Sending client " + ServerUser.AccountName + " game server info: " + lr.ReplyMessage); if (m_IsNewAcct) { ServerUser.Profile.Alias = m_Alias; ServerUser.Profile.Save(MyServer.RequireAuthentication); if (lr.ReplyCode != ReplyType.OK) { lr.ReplyMessage += "\r\n(Account was created, however)"; } } lr.Parms.SetProperty("Alias", ServerUser.Profile.Alias); lr.Parms.SetProperty("ProfilePic", ServerUser.Profile.AddedProperties.GetByteArrayProperty("ProfilePic")); return(lr); }
public override void StartServer() { base.StartServer(); // FORMAT: serverNAME|state|desc string[] services = WispServices.GetInstalledServices(); GameServerInfoGroup gr = new GameServerInfoGroup(); OutboundServerUpdateInterval = 10; gr.ID = "Default"; OutboundServerGroups.Groups.Clear(); OutboundServerGroups.Groups.Add(gr.ID, gr); for (int i = 0; i < services.Length; i++) { string[] parts = services[i].Split(char.Parse("|")); if (parts.Length < 3) { continue; } string name = parts[0]; if (name.ToLower() == "zeus") { continue; // don't connect to self } string state = parts[1]; string desc = parts[2]; object val = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\" + name, "ImagePath", ""); if (val == null) { Log1.Logger("Server").Error("Wisp registry claims that service [" + name + "] is installed, but the Windows registry does not agree."); continue; } string exePath = val.ToString(); string directory = Path.GetDirectoryName(exePath); if (!Directory.Exists(directory)) { Log1.Logger("Server").Error("Windows registry claims that Wisp service [" + name + "] is installed at [" + directory + "] but that directory was not found."); continue; } string targetConfig = exePath + ".config"; if (!File.Exists(targetConfig)) { Log1.Logger("Server").Error("Unable to locate config file [" + targetConfig + "] for service [" + name + "] and so the connection port can't be determnined."); continue; } int port = 0; try { string configContents = File.ReadAllText(targetConfig); int loc = configContents.IndexOf("ListenOnPort"); if (loc < 0) { Log1.Logger("Server").Error("Failed to find 'ListenOnPort' directive in config file [" + targetConfig + "] for service [" + name + "]. Unable to determine port for that service."); continue; } int valLoc = configContents.IndexOf("\"", loc+13); int valEndLoc = configContents.IndexOf("\"", valLoc+1); string sport = configContents.Substring(valLoc+1, valEndLoc-valLoc-1); if (!int.TryParse(sport, out port) || port <= 0) { Log1.Logger("Server").Error("'ListenOnPort' directive in config file [" + targetConfig + "] for service [" + name + "] was in the wrong format - [" + sport +"]. Unable to determine port for that service."); continue; } } catch (Exception e) { Log1.Logger("Server").Error("Failed to read config file [" + targetConfig + "] for service [" + name + "]. Unable to determine port for that service.", e); continue; } GameServerInfo<OutboundServerConnection> gsi = new GameServerInfo<OutboundServerConnection>(); gsi.HostName = "localhost"; gsi.Name = name; string ip = "localhost"; try { gsi.ServiceID = 7; IPHostEntry iphe = Dns.GetHostEntry("localhost"); // this call will delay the server from starting if it doesn't resolve fast enough. bool gotOne = false; foreach (IPAddress addy in iphe.AddressList) { if (addy.AddressFamily == AddressFamily.InterNetwork) { gotOne = true; ip = addy.ToString(); break; } } if (!gotOne) { Log1.Logger("Server.Network").Error("Could not resolve IP address for server " + gsi.Name + " (" + ip + ")"); continue; } } catch (Exception e) { Log1.Logger("Server.Network").Error("Error setting up outbound server connection. " + gsi.Name + " / " + gsi.HostName + " : " + e.Message, e); // try the next address in the config continue; } if (ip.Trim().Length < 1) { // try the next address in the config continue; } gsi.IP = ip; gsi.Port = port; gsi.IsOnline = false; gsi.LastUpdate = DateTime.UtcNow; if (gr.OutboundServers.Exists( con => con.UniqueID == gsi.UniqueID)) { continue; } gr.OutboundServers.Add(gsi); } StartOutboundServerUpdate(); }
protected override GameServerInfo<OutboundServerConnection> GetTargetServerForClusterHandoff(string serverGroup) { GameServerInfo<OutboundServerConnection> gsi = null; List<string> addresses; List<string> ids; List<int> ports; List<int> curConnections; List<int> maxConnections; // Grab all registered content servers. if (DB.Instance.Server_GetRegistrations("", "lobby", out addresses, out ids, out ports, out curConnections, out maxConnections)) { // find the lowest population server int low = 0; float lowRatio = 1f; for (int i = 0; i < ids.Count; i++) { float ratio = (float)curConnections[i] / (float)maxConnections[i]; if (ratio < lowRatio) { lowRatio = ratio; low = i; } } if (lowRatio >= 1) { // All servers are at capacity. return null; } // Create a temp object with latest info from DB gsi = new GameServerInfo<OutboundServerConnection>(); gsi.Name = ids[low]; gsi.IP = addresses[low]; gsi.Port = ports[low]; gsi.CurUsers = curConnections[low]; gsi.MaxUsers = maxConnections[low]; } return gsi; }
/// <summary> /// Loads the outgoing server connections from the App.Config file. /// </summary> private void LoadOutgoingConnections() { ConnectionConfigSection section = null; try { section = (ConnectionConfigSection)ConfigurationManager.GetSection("OutgoingConnections"); } catch (Exception e) { Log1.Logger("Server").Fatal("Error loading config file section 'OutgoingConnections'. " + e.Message); return; } if (ConfigHelper.GetStringConfig("DatabaseConnectivity", "TRUE").ToLower() != "false") { DB.Instance.AddServerGroupSessionConnection("Default", ConfigurationManager.ConnectionStrings["SessionDataConnectionString"].ConnectionString); } OutboundServerUpdateInterval = section == null? int.MaxValue : section.UpdateIntervalSecs; GameServerInfoGroup group = null; if(section != null) { foreach (GroupElement g in section.Groups) { group = new GameServerInfoGroup(); group.SharedHiveKey = g.SharedHiveKey; group.ID = g.ID; // DB session, if exists if (g.SessionDataConnectionString.Length > 0) { DB.Instance.AddServerGroupSessionConnection(group.ID, g.SessionDataConnectionString); } else { DB.Instance.AddServerGroupSessionConnection(group.ID, ConfigurationManager.ConnectionStrings["SessionDataConnectionString"].ConnectionString); } string cm = g.ConnectMode.ToLower(); switch (cm) { case "roundrobin": group.ConnectMode = OutgoingServerConnectMethod.RoundRobin; break; case "random": group.ConnectMode = OutgoingServerConnectMethod.Random; break; default: group.ConnectMode = OutgoingServerConnectMethod.All; break; } foreach (ConnectionElement con in g.ConnectionItems) { try { GameServerInfo<OutboundServerConnection> gsi = new GameServerInfo<OutboundServerConnection>(); gsi.HostName = con.Address; gsi.Name = con.ConnectionName; gsi.ServiceID = con.ServiceID; if (con.SharedHiveKey.Length < 1) { gsi.SharedHiveKey = g.SharedHiveKey; } else { gsi.SharedHiveKey = con.SharedHiveKey; } string ip = con.Address; try { IPHostEntry iphe = Dns.GetHostEntry(ip); // this call will delay the server from starting if it doesn't resolve fast enough. bool gotOne = false; foreach (IPAddress addy in iphe.AddressList) { if (addy.AddressFamily == AddressFamily.InterNetwork) { gotOne = true; ip = addy.ToString(); break; } } if (!gotOne) { Log1.Logger("Server.Network").Error("Could not resolve IP address for server " + gsi.Name + " (" + ip + ")"); continue; } } catch (Exception e) { Log1.Logger("Server.Network").Error("Error setting up outbound server connection. " + gsi.Name + " / " + gsi.HostName + " : " + e.Message, e); // try the next address in the config continue; } if (ip.Trim().Length < 1) { // try the next address in the config continue; } gsi.IP = ip; gsi.Port = con.Port; gsi.IsOnline = false; gsi.LastUpdate = DateTime.UtcNow; if (group.OutboundServers.Exists(xcon => xcon.UniqueID == gsi.UniqueID)) { Log1.Logger("Server").Error("Not adding outbound server [" + gsi.Name + "] as it's destination endpoing [" + gsi.UniqueID + "] matches an existing connection."); continue; } gsi.ServerGroup = group.ID; group.OutboundServers.Add(gsi); } finally { } } } if (group != null) { if (group.ConnectMode == OutgoingServerConnectMethod.Random || group.ConnectMode == OutgoingServerConnectMethod.RoundRobin) { // these two connect methods always start with a random index in the list. this helps a little in balancing the load across many instances of servers, in lieu of a proper load balancer. group.CurConnectionIndex = m_Random.Next(0, group.OutboundServers.Count); } OutboundServerGroups.Groups.Remove(group.ID); OutboundServerGroups.Groups.Add(group.ID, group); } } }
protected override bool HaveServersForService() { GameServerInfo <OutboundServerConnection> cons = GetTargetServerForClusterHandoff(""); return(cons != null); }
/// <summary> /// Once the login server has authenticated us, it will send us a list of server clusters that it knows about. /// After the player has chosen a server cluster to play on (or perhaps the client auto-chooses one), this method /// can be called to petition the login server for handoff to that cluster. The login server, in turn, will /// petition the target cluster for the handoff. Once the login server receives the result of the request, it /// forwards it on to the player. If the petition is successful, the client will then possess an auth ticket which /// can be used to connect to the target sub-server in the requested cluster. /// </summary> /// <param name="whichCluster">the cluster to request</param> /// <param name="targetResource">a specific resource we're interested in on the target cluster, if any. helps route us to the correct sub-server that handles that resource</param> /// <returns>true, if the petition was dispatched, false if the target cluster is offline</returns> public bool PetitionLoginServerForClusterHandoff(GameServerInfo gsi, Guid targetResource) { if (gsi.IsOnline) { m_LoginCon.RequestHandoffToServer(gsi, targetResource); return true; } return false; }
public override void StartServer() { base.StartServer(); // FORMAT: serverNAME|state|desc string[] services = WispServices.GetInstalledServices(); for (int i = 0; i < services.Length; i++) { string[] parts = services[i].Split(char.Parse("|")); if (parts.Length < 3) { continue; } string name = parts[0]; string state = parts[1]; string desc = parts[2]; object val = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\" + name, "ImagePath", ""); if (val == null) { Log1.Logger("Server").Error("Wisp registry claims that service [" + name + "] is installed, but the Windows registry does not agree."); continue; } string exePath = val.ToString(); string directory = Path.GetDirectoryName(exePath); if (!Directory.Exists(directory)) { Log1.Logger("Server").Error("Windows registry claims that Wisp service [" + name + "] is installed at [" + directory + "] but that directory was not found."); continue; } string targetConfig = exePath + ".config"; if (!File.Exists(targetConfig)) { Log1.Logger("Server").Error("Unable to locate config file [" + targetConfig + "] for service [" + name + "] and so the connection port can't be determnined."); continue; } int port = 0; try { string configContents = File.ReadAllText(targetConfig); int loc = configContents.IndexOf("ListenOnPort"); if (loc < 0) { Log1.Logger("Server").Error("Failed to find 'ListenOnPort' directive in config file [" + targetConfig + "] for service [" + name + "]. Unable to determine port for that service."); continue; } int valLoc = configContents.IndexOf("\"", loc + 13); int valEndLoc = configContents.IndexOf("\"", valLoc + 1); string sport = configContents.Substring(valLoc + 1, valEndLoc - valLoc - 1); if (!int.TryParse(sport, out port) || port <= 0) { Log1.Logger("Server").Error("'ListenOnPort' directive in config file [" + targetConfig + "] for service [" + name + "] was in the wrong format - [" + sport + "]. Unable to determine port for that service."); continue; } } catch (Exception e) { Log1.Logger("Server").Error("Failed to read config file [" + targetConfig + "] for service [" + name + "]. Unable to determine port for that service.", e); continue; } GameServerInfo <OutboundServerConnection> gsi = new GameServerInfo <OutboundServerConnection>(); gsi.HostName = "localhost"; gsi.Name = name; string ip = "localhost"; try { gsi.ServiceID = 7; // 7eus IPHostEntry iphe = Dns.GetHostEntry("localhost"); // this call will delay the server from starting if it doesn't resolve fast enough. bool gotOne = false; foreach (IPAddress addy in iphe.AddressList) { if (addy.AddressFamily == AddressFamily.InterNetwork) { gotOne = true; ip = addy.ToString(); break; } } if (!gotOne) { Log1.Logger("Server.Network").Error("Could not resolve IP address for server " + gsi.Name + " (" + ip + ")"); continue; } } catch (Exception e) { Log1.Logger("Server.Network").Error("Error setting up outbound server connection. " + gsi.Name + " / " + gsi.HostName + " : " + e.Message, e); // try the next address in the config continue; } if (ip.Trim().Length < 1) { // try the next address in the config continue; } gsi.IP = ip; gsi.Port = port; gsi.IsOnline = false; gsi.LastUpdate = DateTime.UtcNow; if (OutboundServers.ContainsKey(gsi.UniqueID)) { continue; } OutboundServers.Add(gsi.UniqueID, gsi); } StartOutboundServerUpdate(); }