Example #1
0
        public void DropClient(Connection toDrop, int frame)
        {
            if (!PreConns.Remove(toDrop))
            {
                Conns.Remove(toDrop);

                var dropClient = LobbyInfo.Clients.FirstOrDefault(c1 => c1.Index == toDrop.PlayerIndex);
                if (dropClient == null)
                {
                    return;
                }

                var suffix = "";
                if (State == ServerState.GameStarted)
                {
                    suffix = dropClient.IsObserver ? " (Spectator)" : dropClient.Team != 0 ? " (Team {0})".F(dropClient.Team) : "";
                }
                SendMessage("{0}{1} has disconnected.".F(dropClient.Name, suffix));

                // Send disconnected order, even if still in the lobby
                DispatchOrdersToClients(toDrop, 0, new ServerOrder("Disconnected", "").Serialize());

                LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);

                // Client was the server admin
                // TODO: Reassign admin for game in progress via an order
                if (LobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
                {
                    // Remove any bots controlled by the admin
                    LobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex);

                    var nextAdmin = LobbyInfo.Clients.Where(c1 => c1.Bot == null)
                                    .MinByOrDefault(c => c.Index);

                    if (nextAdmin != null)
                    {
                        nextAdmin.IsAdmin = true;
                        SendMessage("{0} is now the admin.".F(nextAdmin.Name));
                    }
                }

                DispatchOrders(toDrop, frame, new byte[] { 0xbf });

                if (!Conns.Any())
                {
                    FieldLoader.Load(LobbyInfo.GlobalSettings, ModData.Manifest.LobbyDefaults);
                    TempBans.Clear();
                }

                if (Conns.Any() || LobbyInfo.GlobalSettings.Dedicated)
                {
                    SyncLobbyClients();
                }

                if (!LobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin)
                {
                    Shutdown();
                }
            }

            try
            {
                toDrop.Socket.Disconnect(false);
            }
            catch { }

            SetOrderLag();
        }
Example #2
0
			public ResourceTypeInfo(MiniYaml yaml)
			{
				FieldLoader.Load(this, yaml);
			}
Example #3
0
        public GameServer(MiniYaml yaml)
        {
            FieldLoader.Load(this, yaml);

            // Games advertised using the old API used a single Mods field
            if (Mod == null || Version == null)
            {
                var modsNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Mods");
                if (modsNode != null)
                {
                    var modVersion = modsNode.Value.Value.Split('@');
                    Mod     = modVersion[0];
                    Version = modVersion[1];
                }
            }

            // Games advertised using the old API calculated the play time locally
            if (State == 2 && PlayTime < 0)
            {
                DateTime startTime;
                if (DateTime.TryParse(Started, out startTime))
                {
                    PlayTime = (int)(DateTime.UtcNow - startTime).TotalSeconds;
                }
            }

            ExternalMod external;
            var         externalKey = ExternalMod.MakeKey(Mod, Version);

            if (Game.ExternalMods.TryGetValue(externalKey, out external) && external.Version == Version)
            {
                IsCompatible = true;
            }

            // Games advertised using the old API used local mod metadata
            if (string.IsNullOrEmpty(ModTitle))
            {
                Manifest mod;

                if (external != null && external.Version == Version)
                {
                    // Use external mod registration to populate the section header
                    ModTitle = external.Title;
                }
                else if (Game.Mods.TryGetValue(Mod, out mod))
                {
                    // Use internal mod data to populate the section header, but
                    // on-connect switching must use the external mod plumbing.
                    ModTitle = mod.Metadata.Title;
                }
                else
                {
                    // Some platforms (e.g. macOS) package each mod separately, so the Mods check above won't work.
                    // Guess based on the most recent ExternalMod instead.
                    var guessMod = Game.ExternalMods.Values
                                   .OrderByDescending(m => m.Version)
                                   .FirstOrDefault(m => m.Id == Mod);

                    if (guessMod != null)
                    {
                        ModTitle = "{0}".F(guessMod.Title);
                    }
                    else
                    {
                        ModTitle = "Unknown mod: {0}".F(Mod);
                    }
                }
            }

            var mapAvailable = Game.Settings.Game.AllowDownloading || Game.ModData.MapCache[Map].Status == MapStatus.Available;

            IsJoinable = IsCompatible && State == 1 && mapAvailable;
        }
Example #4
0
        public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData)
        {
            Log.AddChannel("server", "server.log");

            listener = new TcpListener(endpoint);
            listener.Start();
            var localEndpoint = (IPEndPoint)listener.LocalEndpoint;

            Ip   = localEndpoint.Address;
            Port = localEndpoint.Port;

            Settings = settings;

            Settings.Name = OpenRA.Settings.SanitizedServerName(Settings.Name);

            ModData = modData;

            randomSeed = (int)DateTime.Now.ToBinary();

            if (Settings.AllowPortForward)
            {
                UPnP.ForwardPort(3600);
            }

            foreach (var trait in modData.Manifest.ServerTraits)
            {
                serverTraits.Add(modData.ObjectCreator.CreateObject <ServerTrait>(trait));
            }

            LobbyInfo = new Session
            {
                GlobalSettings =
                {
                    RandomSeed = randomSeed,
                    Map        = settings.Map,
                    ServerName = settings.Name,
                    Dedicated  = settings.Dedicated
                }
            };

            FieldLoader.Load(LobbyInfo.GlobalSettings, modData.Manifest.LobbyDefaults);

            foreach (var t in serverTraits.WithInterface <INotifyServerStart>())
            {
                t.ServerStarted(this);
            }

            Log.Write("server", "Initial mod: {0}", ModData.Manifest.Mod.Id);
            Log.Write("server", "Initial map: {0}", LobbyInfo.GlobalSettings.Map);

            new Thread(_ =>
            {
                var timeout = serverTraits.WithInterface <ITick>().Min(t => t.TickTimeout);
                for (;;)
                {
                    var checkRead = new List <Socket>();
                    if (State == ServerState.WaitingPlayers)
                    {
                        checkRead.Add(listener.Server);
                    }

                    checkRead.AddRange(Conns.Select(c => c.Socket));
                    checkRead.AddRange(PreConns.Select(c => c.Socket));

                    if (checkRead.Count > 0)
                    {
                        Socket.Select(checkRead, null, null, timeout);
                    }

                    if (State == ServerState.ShuttingDown)
                    {
                        EndGame();
                        break;
                    }

                    foreach (var s in checkRead)
                    {
                        if (s == listener.Server)
                        {
                            AcceptConnection();
                        }
                        else if (PreConns.Count > 0)
                        {
                            var p = PreConns.SingleOrDefault(c => c.Socket == s);
                            if (p != null)
                            {
                                p.ReadData(this);
                            }
                        }
                        else if (Conns.Count > 0)
                        {
                            var conn = Conns.SingleOrDefault(c => c.Socket == s);
                            if (conn != null)
                            {
                                conn.ReadData(this);
                            }
                        }
                    }

                    foreach (var t in serverTraits.WithInterface <ITick>())
                    {
                        t.Tick(this);
                    }

                    if (State == ServerState.ShuttingDown)
                    {
                        EndGame();
                        if (Settings.AllowPortForward)
                        {
                            UPnP.RemovePortforward();
                        }
                        break;
                    }
                }

                foreach (var t in serverTraits.WithInterface <INotifyServerShutdown>())
                {
                    t.ServerShutdown(this);
                }

                PreConns.Clear();
                Conns.Clear();
                try { listener.Stop(); }
                catch { }
            })
            {
                IsBackground = true
            }.Start();
        }
Example #5
0
 public Consideration(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
        public void ClientJoined(OpenRA.Server.Server server, Connection conn)
        {
            if (server.LobbyInfo.ClientWithIndex(conn.PlayerIndex).IsAdmin)
            {
                return;
            }

            var defaults = new Session.Global();

            FieldLoader.Load(defaults, Game.ModData.Manifest.LobbyDefaults);

            if (server.LobbyInfo.GlobalSettings.FragileAlliances != defaults.FragileAlliances)
            {
                server.SendOrderTo(conn, "Message", "Diplomacy Changes: {0}".F(server.LobbyInfo.GlobalSettings.FragileAlliances));
            }

            if (server.LobbyInfo.GlobalSettings.AllowCheats != defaults.AllowCheats)
            {
                server.SendOrderTo(conn, "Message", "Allow Cheats: {0}".F(server.LobbyInfo.GlobalSettings.AllowCheats));
            }

            if (server.LobbyInfo.GlobalSettings.Shroud != defaults.Shroud)
            {
                server.SendOrderTo(conn, "Message", "Shroud: {0}".F(server.LobbyInfo.GlobalSettings.Shroud));
            }

            if (server.LobbyInfo.GlobalSettings.Fog != defaults.Fog)
            {
                server.SendOrderTo(conn, "Message", "Fog of war: {0}".F(server.LobbyInfo.GlobalSettings.Fog));
            }

            if (server.LobbyInfo.GlobalSettings.Crates != defaults.Crates)
            {
                server.SendOrderTo(conn, "Message", "Crates Appear: {0}".F(server.LobbyInfo.GlobalSettings.Crates));
            }

            if (server.LobbyInfo.GlobalSettings.Creeps != defaults.Creeps)
            {
                server.SendOrderTo(conn, "Message", "Creeps Spawn: {0}".F(server.LobbyInfo.GlobalSettings.Creeps));
            }

            if (server.LobbyInfo.GlobalSettings.AllyBuildRadius != defaults.AllyBuildRadius)
            {
                server.SendOrderTo(conn, "Message", "Build off Ally ConYards: {0}".F(server.LobbyInfo.GlobalSettings.AllyBuildRadius));
            }

            if (server.LobbyInfo.GlobalSettings.StartingUnitsClass != defaults.StartingUnitsClass)
            {
                var startUnitsInfo = server.Map.Rules.Actors["world"].Traits.WithInterface <MPStartUnitsInfo>();
                var selectedClass  = startUnitsInfo.Where(u => u.Class == server.LobbyInfo.GlobalSettings.StartingUnitsClass).Select(u => u.ClassName).FirstOrDefault();
                var className      = selectedClass != null ? selectedClass : server.LobbyInfo.GlobalSettings.StartingUnitsClass;
                server.SendOrderTo(conn, "Message", "Starting Units: {0}".F(className));
            }

            if (server.LobbyInfo.GlobalSettings.StartingCash != defaults.StartingCash)
            {
                server.SendOrderTo(conn, "Message", "Starting Cash: ${0}".F(server.LobbyInfo.GlobalSettings.StartingCash));
            }

            if (server.LobbyInfo.GlobalSettings.TechLevel != defaults.TechLevel)
            {
                server.SendOrderTo(conn, "Message", "Tech Level: {0}".F(server.LobbyInfo.GlobalSettings.TechLevel));
            }

            if (server.LobbyInfo.GlobalSettings.ShortGame != defaults.ShortGame)
            {
                server.SendOrderTo(conn, "Message", "Short Game: {0}".F(server.LobbyInfo.GlobalSettings.ShortGame));
            }
        }
Example #7
0
 public LocalizedMessage(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Example #8
0
 public WeaponInfo(string name, MiniYaml content)
 {
     FieldLoader.Load(this, content);
 }
Example #9
0
        public RegisteredProfileTooltipLogic(Widget widget, WorldRenderer worldRenderer, ModData modData, Session.Client client)
        {
            playerDatabase = modData.Manifest.Get <PlayerDatabase>();

            var header         = widget.Get("HEADER");
            var badgeContainer = widget.Get("BADGES_CONTAINER");
            var badgeSeparator = badgeContainer.GetOrNull("SEPARATOR");

            var profileHeader = header.Get("PROFILE_HEADER");
            var messageHeader = header.Get("MESSAGE_HEADER");
            var message       = messageHeader.Get <LabelWidget>("MESSAGE");
            var messageFont   = Game.Renderer.Fonts[message.Font];

            profileHeader.IsVisible = () => profileLoaded;
            messageHeader.IsVisible = () => !profileLoaded;

            var profileWidth = 0;
            var messageText  = "Loading player profile...";
            var messageWidth = messageFont.Measure(messageText).X + 2 * message.Bounds.Left;

            Action <DownloadDataCompletedEventArgs> onQueryComplete = i =>
            {
                try
                {
                    if (i.Error == null)
                    {
                        var yaml = MiniYaml.FromString(Encoding.UTF8.GetString(i.Result)).First();
                        if (yaml.Key == "Player")
                        {
                            profile = FieldLoader.Load <PlayerProfile>(yaml.Value);
                            Game.RunAfterTick(() =>
                            {
                                var nameLabel = profileHeader.Get <LabelWidget>("PROFILE_NAME");
                                var nameFont  = Game.Renderer.Fonts[nameLabel.Font];
                                var rankLabel = profileHeader.Get <LabelWidget>("PROFILE_RANK");
                                var rankFont  = Game.Renderer.Fonts[rankLabel.Font];

                                var adminContainer = profileHeader.Get("GAME_ADMIN");
                                var adminLabel     = adminContainer.Get <LabelWidget>("LABEL");
                                var adminFont      = Game.Renderer.Fonts[adminLabel.Font];

                                var headerSizeOffset = profileHeader.Bounds.Height - messageHeader.Bounds.Height;

                                nameLabel.GetText = () => profile.ProfileName;
                                rankLabel.GetText = () => profile.ProfileRank;

                                profileWidth = Math.Max(profileWidth, nameFont.Measure(profile.ProfileName).X + 2 * nameLabel.Bounds.Left);
                                profileWidth = Math.Max(profileWidth, rankFont.Measure(profile.ProfileRank).X + 2 * rankLabel.Bounds.Left);

                                header.Bounds.Height    += headerSizeOffset;
                                badgeContainer.Bounds.Y += header.Bounds.Height;
                                if (client.IsAdmin)
                                {
                                    profileWidth = Math.Max(profileWidth, adminFont.Measure(adminLabel.Text).X + 2 * adminLabel.Bounds.Left);

                                    adminContainer.IsVisible     = () => true;
                                    profileHeader.Bounds.Height += adminLabel.Bounds.Height;
                                    header.Bounds.Height        += adminLabel.Bounds.Height;
                                    badgeContainer.Bounds.Y     += adminLabel.Bounds.Height;
                                }

                                Func <int, int> negotiateWidth = badgeWidth =>
                                {
                                    profileWidth = Math.Min(Math.Max(badgeWidth, profileWidth), widget.Bounds.Width);
                                    return(profileWidth);
                                };

                                if (profile.Badges.Any())
                                {
                                    var badges = Ui.LoadWidget("PLAYER_PROFILE_BADGES_INSERT", badgeContainer, new WidgetArgs()
                                    {
                                        { "worldRenderer", worldRenderer },
                                        { "profile", profile },
                                        { "negotiateWidth", negotiateWidth }
                                    });

                                    if (badges.Bounds.Height > 0)
                                    {
                                        badgeContainer.Bounds.Height = badges.Bounds.Height;
                                        badgeContainer.IsVisible     = () => true;
                                    }
                                }

                                profileWidth         = Math.Min(profileWidth, widget.Bounds.Width);
                                header.Bounds.Width  = widget.Bounds.Width = badgeContainer.Bounds.Width = profileWidth;
                                widget.Bounds.Height = header.Bounds.Height + badgeContainer.Bounds.Height;

                                if (badgeSeparator != null)
                                {
                                    badgeSeparator.Bounds.Width = profileWidth - 2 * badgeSeparator.Bounds.X;
                                }

                                profileLoaded = true;
                            });
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Write("debug", "Failed to parse player data result with exception: {0}", e);
                }
                finally
                {
                    if (profile == null)
                    {
                        messageText         = "Failed to load player profile.";
                        messageWidth        = messageFont.Measure(messageText).X + 2 * message.Bounds.Left;
                        header.Bounds.Width = widget.Bounds.Width = messageWidth;
                    }
                }
            };

            message.GetText        = () => messageText;
            header.Bounds.Height  += messageHeader.Bounds.Height;
            header.Bounds.Width    = widget.Bounds.Width = messageWidth;
            widget.Bounds.Height   = header.Bounds.Height;
            badgeContainer.Visible = false;

            new Download(playerDatabase.Profile + client.Fingerprint, _ => { }, onQueryComplete);
        }
Example #10
0
        static object LoadBuildingCategories(MiniYaml yaml)
        {
            var categories = yaml.Nodes.First(n => n.Key == "BuildingCommonNames");

            return(FieldLoader.Load <BuildingCategories>(categories.Value));
        }
Example #11
0
 public AutoConnectInfo(MiniYaml my)
 {
     FieldLoader.Load(this, my);
 }
Example #12
0
        public void DropClient(Connection toDrop)
        {
            if (preConns.Contains(toDrop))
            {
                preConns.Remove(toDrop);
            }
            else
            {
                conns.Remove(toDrop);

                var dropClient = lobbyInfo.Clients.FirstOrDefault(c1 => c1.Index == toDrop.PlayerIndex);
                if (dropClient == null)
                {
                    return;
                }

                // Send disconnected order, even if still in the lobby
                SendMessage("{0} has disconnected.".F(dropClient.Name));
                DispatchOrdersToClients(toDrop, 0, new ServerOrder("Disconnected", "").Serialize());

                lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);

                // Client was the server admin
                // TODO: Reassign admin for game in progress via an order
                if (lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
                {
                    // Remove any bots controlled by the admin
                    lobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex);

                    var nextAdmin = lobbyInfo.Clients.Where(c1 => c1.Bot == null)
                                    .OrderBy(c => c.Index).FirstOrDefault();

                    if (nextAdmin != null)
                    {
                        nextAdmin.IsAdmin = true;
                        SendMessage("{0} is now the admin.".F(nextAdmin.Name));
                    }
                }

                DispatchOrders(toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf });

                if (!conns.Any())
                {
                    FieldLoader.Load(lobbyInfo.GlobalSettings, ModData.Manifest.LobbyDefaults);
                    TempBans.Clear();
                }

                if (conns.Any() || lobbyInfo.GlobalSettings.Dedicated)
                {
                    SyncLobbyInfo();
                }

                if (!lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin)
                {
                    Shutdown();
                }
            }

            try
            {
                toDrop.socket.Disconnect(false);
            }
            catch { }

            SetOrderLag();
        }
Example #13
0
 public PlayerReference(MiniYaml my)
 {
     FieldLoader.Load(this, my);
 }
Example #14
0
 public static ClientPing Deserialize(MiniYaml data)
 {
     return(FieldLoader.Load <ClientPing>(data));
 }
Example #15
0
 public ClassicAirstrikePowerSquadMember(MiniYamlNode yamlNode)
 {
     UnitType = yamlNode.Key;
     FieldLoader.Load(this, yamlNode.Value);
 }
Example #16
0
 public static Slot Deserialize(MiniYaml data)
 {
     return(FieldLoader.Load <Slot>(data));
 }
Example #17
0
        void ValidateClient(Connection newConn, string data)
        {
            try
            {
                if (State == ServerState.GameStarted)
                {
                    Log.Write("server", "Rejected connection from {0}; game is already started.",
                              newConn.Socket.RemoteEndPoint);

                    SendOrderTo(newConn, "ServerError", "The game has already started");
                    DropClient(newConn);
                    return;
                }

                var handshake = HandshakeResponse.Deserialize(data);

                if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password)
                {
                    var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password";
                    SendOrderTo(newConn, "AuthenticationError", message);
                    DropClient(newConn);
                    return;
                }

                var ipAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address;
                var client    = new Session.Client
                {
                    Name                = OpenRA.Settings.SanitizedPlayerName(handshake.Client.Name),
                    IPAddress           = ipAddress.ToString(),
                    AnonymizedIPAddress = Type != ServerType.Local && Settings.ShareAnonymizedIPs ? Session.AnonymizeIP(ipAddress) : null,
                    Location            = GeoIP.LookupCountry(ipAddress),
                    Index               = newConn.PlayerIndex,
                    PreferredColor      = handshake.Client.PreferredColor,
                    Color               = handshake.Client.Color,
                    Faction             = "Random",
                    SpawnPoint          = 0,
                    Team                = 0,
                    State               = Session.ClientState.Invalid,
                };

                if (ModData.Manifest.Id != handshake.Mod)
                {
                    Log.Write("server", "Rejected connection from {0}; mods do not match.",
                              newConn.Socket.RemoteEndPoint);

                    SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod");
                    DropClient(newConn);
                    return;
                }

                if (ModData.Manifest.Metadata.Version != handshake.Version)
                {
                    Log.Write("server", "Rejected connection from {0}; Not running the same version.",
                              newConn.Socket.RemoteEndPoint);

                    SendOrderTo(newConn, "ServerError", "Server is running an incompatible version");
                    DropClient(newConn);
                    return;
                }

                if (handshake.OrdersProtocol != ProtocolVersion.Orders)
                {
                    Log.Write("server", "Rejected connection from {0}; incompatible Orders protocol version {1}.",
                              newConn.Socket.RemoteEndPoint, handshake.OrdersProtocol);

                    SendOrderTo(newConn, "ServerError", "Server is running an incompatible protocol");
                    DropClient(newConn);
                    return;
                }

                // Check if IP is banned
                var bans = Settings.Ban.Union(TempBans);
                if (bans.Contains(client.IPAddress))
                {
                    Log.Write("server", "Rejected connection from {0}; Banned.", newConn.Socket.RemoteEndPoint);
                    SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IPAddress) ? "banned" : "temporarily banned"));
                    DropClient(newConn);
                    return;
                }

                Action completeConnection = () =>
                {
                    client.Slot    = LobbyInfo.FirstEmptySlot();
                    client.IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin);

                    if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators)
                    {
                        SendOrderTo(newConn, "ServerError", "The game is full");
                        DropClient(newConn);
                        return;
                    }

                    if (client.Slot != null)
                    {
                        SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]);
                    }
                    else
                    {
                        client.Color = Color.White;
                    }

                    // Promote connection to a valid client
                    PreConns.Remove(newConn);
                    Conns.Add(newConn);
                    LobbyInfo.Clients.Add(client);
                    newConn.Validated = true;

                    var clientPing = new Session.ClientPing {
                        Index = client.Index
                    };
                    LobbyInfo.ClientPings.Add(clientPing);

                    Log.Write("server", "Client {0}: Accepted connection from {1}.",
                              newConn.PlayerIndex, newConn.Socket.RemoteEndPoint);

                    if (client.Fingerprint != null)
                    {
                        Log.Write("server", "Client {0}: Player fingerprint is {1}.",
                                  newConn.PlayerIndex, client.Fingerprint);
                    }

                    foreach (var t in serverTraits.WithInterface <IClientJoined>())
                    {
                        t.ClientJoined(this, newConn);
                    }

                    SyncLobbyInfo();

                    Log.Write("server", "{0} ({1}) has joined the game.",
                              client.Name, newConn.Socket.RemoteEndPoint);

                    // Report to all other players
                    SendMessage("{0} has joined the game.".F(client.Name), newConn);

                    // Send initial ping
                    SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture));

                    if (Type == ServerType.Dedicated)
                    {
                        var motdFile = Platform.ResolvePath(Platform.SupportDirPrefix, "motd.txt");
                        if (!File.Exists(motdFile))
                        {
                            File.WriteAllText(motdFile, "Welcome, have fun and good luck!");
                        }

                        var motd = File.ReadAllText(motdFile);
                        if (!string.IsNullOrEmpty(motd))
                        {
                            SendOrderTo(newConn, "Message", motd);
                        }
                    }

                    if (Map.DefinesUnsafeCustomRules)
                    {
                        SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change.");
                    }

                    if (!LobbyInfo.GlobalSettings.EnableSingleplayer)
                    {
                        SendOrderTo(newConn, "Message", TwoHumansRequiredText);
                    }
                    else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
                    {
                        SendOrderTo(newConn, "Message", "Bots have been disabled on this map.");
                    }
                };

                if (Type == ServerType.Local)
                {
                    // Local servers can only be joined by the local client, so we can trust their identity without validation
                    client.Fingerprint = handshake.Fingerprint;
                    completeConnection();
                }
                else if (!string.IsNullOrEmpty(handshake.Fingerprint) && !string.IsNullOrEmpty(handshake.AuthSignature))
                {
                    waitingForAuthenticationCallback++;

                    Action <DownloadDataCompletedEventArgs> onQueryComplete = i =>
                    {
                        PlayerProfile profile = null;

                        if (i.Error == null)
                        {
                            try
                            {
                                var yaml = MiniYaml.FromString(Encoding.UTF8.GetString(i.Result)).First();
                                if (yaml.Key == "Player")
                                {
                                    profile = FieldLoader.Load <PlayerProfile>(yaml.Value);

                                    var publicKey  = Encoding.ASCII.GetString(Convert.FromBase64String(profile.PublicKey));
                                    var parameters = CryptoUtil.DecodePEMPublicKey(publicKey);
                                    if (!profile.KeyRevoked && CryptoUtil.VerifySignature(parameters, newConn.AuthToken, handshake.AuthSignature))
                                    {
                                        client.Fingerprint = handshake.Fingerprint;
                                        Log.Write("server", "{0} authenticated as {1} (UID {2})", newConn.Socket.RemoteEndPoint,
                                                  profile.ProfileName, profile.ProfileID);
                                    }
                                    else if (profile.KeyRevoked)
                                    {
                                        profile = null;
                                        Log.Write("server", "{0} failed to authenticate as {1} (key revoked)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint);
                                    }
                                    else
                                    {
                                        profile = null;
                                        Log.Write("server", "{0} failed to authenticate as {1} (signature verification failed)",
                                                  newConn.Socket.RemoteEndPoint, handshake.Fingerprint);
                                    }
                                }
                                else
                                {
                                    Log.Write("server", "{0} failed to authenticate as {1} (invalid server response: `{2}` is not `Player`)",
                                              newConn.Socket.RemoteEndPoint, handshake.Fingerprint, yaml.Key);
                                }
                            }
                            catch (Exception ex)
                            {
                                Log.Write("server", "{0} failed to authenticate as {1} (exception occurred)",
                                          newConn.Socket.RemoteEndPoint, handshake.Fingerprint);
                                Log.Write("server", ex.ToString());
                            }
                        }
                        else
                        {
                            Log.Write("server", "{0} failed to authenticate as {1} (server error: `{2}`)",
                                      newConn.Socket.RemoteEndPoint, handshake.Fingerprint, i.Error);
                        }

                        delayedActions.Add(() =>
                        {
                            var notAuthenticated = Type == ServerType.Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any());
                            var blacklisted      = Type == ServerType.Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID);
                            var notWhitelisted   = Type == ServerType.Dedicated && Settings.ProfileIDWhitelist.Any() &&
                                                   (profile == null || !Settings.ProfileIDWhitelist.Contains(profile.ProfileID));

                            if (notAuthenticated)
                            {
                                Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
                                SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
                                DropClient(newConn);
                            }
                            else if (blacklisted || notWhitelisted)
                            {
                                if (blacklisted)
                                {
                                    Log.Write("server", "Rejected connection from {0}; In server blacklist.", newConn.Socket.RemoteEndPoint);
                                }
                                else
                                {
                                    Log.Write("server", "Rejected connection from {0}; Not in server whitelist.", newConn.Socket.RemoteEndPoint);
                                }

                                SendOrderTo(newConn, "ServerError", "You do not have permission to join this server");
                                DropClient(newConn);
                            }
                            else
                            {
                                completeConnection();
                            }

                            waitingForAuthenticationCallback--;
                        }, 0);
                    };

                    new Download(playerDatabase.Profile + handshake.Fingerprint, _ => { }, onQueryComplete);
                }
                else
                {
                    if (Type == ServerType.Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any()))
                    {
                        Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
                        SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
                        DropClient(newConn);
                    }
                    else
                    {
                        completeConnection();
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Write("server", "Dropping connection {0} because an error occurred:", newConn.Socket.RemoteEndPoint);
                Log.Write("server", ex.ToString());
                DropClient(newConn);
            }
        }
Example #18
0
 public WarheadInfo(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Example #19
0
 public WeaponInfo(string name, MiniYaml content)
 {
     FieldLoader.Load(this, content);
     validTargetSet   = new HashSet <string>(ValidTargets);
     invalidTargetSet = new HashSet <string>(InvalidTargets);
 }
Example #20
0
 public SupportPowerDecision(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Example #21
0
 public static Global Deserialize(MiniYaml data)
 {
     return(FieldLoader.Load <Global>(data));
 }