Esempio n. 1
0
        /// <summary>
        /// Отправляем список публичных комнат в чате.
        /// Сейчас фейкает только один чат рум GPG1 с названием "Room 1"
        /// Игра сама подставит красивое имя из HTTP данных о списке комнат
        /// </summary>
        /// <param name="validate">Строка валидации запроса. Должна быть получена от игры</param>
        void SendChatRooms(TcpPortHandler handler, TcpClientNode node, string validate)
        {
            var bytes = new List <byte>();

            //var remoteEndPoint = handler.RemoteEndPoint;
            //bytes.AddRange(remoteEndPoint.Address.GetAddressBytes());
            bytes.AddRange(IPAddress.Loopback.GetAddressBytes());

            byte[] value2 = BitConverter.GetBytes((ushort)6500);

            bytes.AddRange(BitConverter.IsLittleEndian ? value2.Reverse() : value2);

            bytes.Add(5); // fields count
            bytes.Add(0);


            // Забивает поля, которые нужны игре. В этом же порядке надо будет пихнуть значения дальше для каждой комнаты
            bytes.AddRange("hostname".ToAsciiBytes());
            bytes.Add(0);
            bytes.Add(0);
            bytes.AddRange("numwaiting".ToAsciiBytes());
            bytes.Add(0);
            bytes.Add(0);
            bytes.AddRange("maxwaiting".ToAsciiBytes());
            bytes.Add(0);
            bytes.Add(0);
            bytes.AddRange("numservers".ToAsciiBytes());
            bytes.Add(0);
            bytes.Add(0);
            bytes.AddRange("numplayersname".ToAsciiBytes());
            bytes.Add(0);
            bytes.Add(0);

            // Изначально было 10 комнат в игре, но мы сделаем только одну и весь код написан для синхронизации чата в игре с чатом из лаунчера

            // for (int i = 1; i <= 10; i++)
            // {

            // Странный байт в начале инфы о комнате
            bytes.Add(81);

            // инфа об IP комнаты, но игре на нее пофиг
            var b2 = BitConverter.GetBytes((long)1);

            bytes.Add(b2[3]);
            bytes.Add(b2[2]);
            bytes.Add(b2[1]);
            bytes.Add(b2[0]);

            // инфа о порте комнаты, но игре на нее пофиг
            bytes.Add(0);
            bytes.Add(0);

            // Скрытое название комнаты. Только такой формат принимает с цифрой в конце
            bytes.Add(255);
            bytes.AddRange("Room 1".ToAsciiBytes());
            bytes.Add(0);

            // Количество игроков в комнате
            bytes.Add(255);
            bytes.AddRange(_emulationAdapter.ActivePlayersCount.ToString().ToAsciiBytes());
            bytes.Add(0);

            bytes.Add(255);
            bytes.AddRange("1000".ToAsciiBytes());
            bytes.Add(0);

            bytes.Add(255);
            bytes.AddRange("1".ToAsciiBytes());
            bytes.Add(0);

            bytes.Add(255);
            bytes.AddRange("20".ToAsciiBytes());
            bytes.Add(0);
            // }

            // Непонятный набор байт в конце, но без него не сработает
            bytes.AddRange(new byte[] { 0, 255, 255, 255, 255 });

            var array = bytes.ToArray();

            // Шифруем алгоритмом спая. Участвует строка валидации и уникальный ключ игры
            byte[] enc = GSEncoding.Encode(_gameGSkeyBytes, validate.ToAsciiBytes(), array, array.LongLength);

            handler.Send(node, enc);

            handler.KillClient(node);
        }
 void RestartServices(TcpPortHandler handler, TcpClientNode node)
 {
     // Получение 0 байт говорит о том, что клиент хочет прекратить взаимодействие.
     // Сбрасываем все соединения
     Restart();
 }
Esempio n. 3
0
        /// <summary>
        /// Обратывает строку IRC чата и вызывает соответствующий метод обработчик команды
        /// </summary>
        void HandleChatLine(TcpPortHandler handler, TcpClientNode node, string line)
        {
            var values = GetIrcChatLineValues(line);

            if (line.StartsWith("LOGIN", StringComparison.OrdinalIgnoreCase))
            {
                HandleLoginCommand(handler, node, values); return;
            }
            if (line.StartsWith("USRIP", StringComparison.OrdinalIgnoreCase))
            {
                HandleUsripCommand(handler, node, values); return;
            }
            if (line.StartsWith("CRYPT", StringComparison.OrdinalIgnoreCase))
            {
                HandleCryptCommand(handler, node, values); return;
            }
            if (line.StartsWith("USER", StringComparison.OrdinalIgnoreCase))
            {
                HandleUserCommand(handler, node, values); return;
            }
            if (line.StartsWith("NICK", StringComparison.OrdinalIgnoreCase))
            {
                HandleNickCommand(handler, node, values); return;
            }
            if (line.StartsWith("CDKEY", StringComparison.OrdinalIgnoreCase))
            {
                HandleCdkeyCommand(handler, node, values); return;
            }
            if (line.StartsWith("JOIN", StringComparison.OrdinalIgnoreCase))
            {
                HandleJoinCommand(handler, node, line, values); return;
            }
            if (line.StartsWith("MODE", StringComparison.OrdinalIgnoreCase))
            {
                HandleModeCommand(handler, node, values); return;
            }
            if (line.StartsWith("QUIT", StringComparison.OrdinalIgnoreCase))
            {
                HandleQuitCommand(handler, values); return;
            }
            if (line.StartsWith("PRIVMSG", StringComparison.OrdinalIgnoreCase))
            {
                HandlePrivmsgCommand(handler, values); return;
            }
            if (line.StartsWith("SETCKEY", StringComparison.OrdinalIgnoreCase))
            {
                HandleSetckeyCommand(handler, node, line, values); return;
            }
            if (line.StartsWith("GETCKEY", StringComparison.OrdinalIgnoreCase))
            {
                HandleGetckeyCommand(handler, node, values); return;
            }
            if (line.StartsWith("TOPIC", StringComparison.OrdinalIgnoreCase))
            {
                HandleTopicCommand(handler, node, values); return;
            }
            if (line.StartsWith("PART", StringComparison.OrdinalIgnoreCase))
            {
                HandlePartCommand(handler, values); return;
            }
            if (line.StartsWith("UTM", StringComparison.OrdinalIgnoreCase))
            {
                HandleUtmCommand(handler, line); return;
            }
            if (line.StartsWith("PING", StringComparison.OrdinalIgnoreCase))
            {
                HandlePingCommand(handler, node, values); return;
            }

            Debugger.Break();
        }
Esempio n. 4
0
        void OnServerRetrieveReceived(TcpPortHandler handler, TcpClientNode node, byte[] buffer, int count)
        {
            var str = buffer.ToASCII(count);

            LogTrace("RETRIEVE " + str);

            var endPoint = node.RemoteEndPoint;

            if (endPoint == null)
            {
                handler.KillClient(node);
                return;
            }

            string[] data = str.Split(new char[] { '\x00' }, StringSplitOptions.RemoveEmptyEntries);

            string validate = data[4];
            string filter   = null;

            bool isAutomatch = false;

            if (validate.Length > 8)
            {
                filter   = validate.Substring(8);
                validate = validate.Substring(0, 8);
            }
            else
            {
                //Log(Category, "ROOMS REQUEST - "+ data[2]);

                isAutomatch = data[2].EndsWith("am");

                if (!isAutomatch)
                {
                    SendChatRooms(handler, node, validate);
                    return;
                }
            }

            var lobbies = _emulationAdapter.GetOpenedLobbies();

            try
            {
                // var currentRating = ServerContext.ChatServer.CurrentRating;

                /*for (int i = 0; i < lobbies.Length; i++)
                 * {
                 *  var server = lobbies[i];
                 *
                 *  //server["score_"] = GetCurrentRating(server.MaxPlayers);
                 * }*/

                var fields = data[5].Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);

                var unencryptedBytes = ParseHelper.PackServerList(endPoint, lobbies, fields, isAutomatch);

                _lastLoadedLobbies.Clear();

                for (int i = 0; i < lobbies.Length; i++)
                {
                    var server      = lobbies[i];
                    var address     = server.HostIP ?? server.LocalIP;
                    var port        = ushort.Parse(server.HostPort ?? server.LocalPort);
                    var channelHash = ChatCrypt.PiStagingRoomHash(address, address, port);

                    Log($"HASHFOR {address}:{port}  {channelHash}");

                    server.RoomHash = channelHash;
                    _lastLoadedLobbies[channelHash] = server;
                }

                Log("SERVERS VALIDATE VALUE ~" + validate + "~");

                var encryptedBytes = GSEncoding.Encode(_gameGSkeyBytes, validate.ToAsciiBytes(), unencryptedBytes, unencryptedBytes.LongLength);

                Log("SERVERS bytes " + encryptedBytes.Length);

                int autoGames   = 0;
                int customGames = 0;
                // TODO вынести в отдельно
                for (int i = 0; i < lobbies.Length; i++)
                {
                    var server = lobbies[i];
                    if (server.Ranked)
                    {
                        autoGames++;
                    }
                    else
                    {
                        customGames++;
                    }
                }

                //CoreContext.ClientServer.SendAsServerMessage(
                //    "Received game list: " + customGames + " - custom; " + autoGames +
                //    " - auto; Mod: "+ CoreContext.ThunderHawkModManager.CurrentModName);

                handler.Send(node, encryptedBytes);
            }
            finally
            {
                handler.KillClient(node);
            }
        }
 void KillNode(TcpPortHandler handler, TcpClientNode node)
 {
     // Получение 0 байт говорит о том, что клиент хочет прекратить взаимодействие.
     handler.KillClient(node);
 }
        void OnReceive(TcpClientNode node, Task <int> task)
        {
            try
            {
                if (task.IsCanceled)
                {
                    return;
                }

                if (task.IsFaulted)
                {
                    throw task.Exception.GetInnerException();
                }

                var count = task.Result;

                if (count == 0)
                {
                    _zeroHandlerDelegate?.Invoke(this, node);
                }
                else
                {
                    _handlerDelegate(this, node, node.Buffer, count);
                }
            }
            catch (OperationCanceledException)
            {
                KillClient(node);
            }
            catch (InvalidOperationException)
            {
                KillClient(node);
            }
            catch (SocketException)
            {
                KillClient(node);
            }
            catch (Exception ex)
            {
                KillClient(node);
                _exceptionHandlerDelegate?.Invoke(ex, false, _port);
            }
            finally
            {
                try
                {
                    if (node.Client.Connected)
                    {
                        var source = _tokenSource;

                        if (source != null)
                        {
                            node.Client.ReceiveAsync(new ArraySegment <byte>(node.Buffer, 0, node.Buffer.Length), SocketFlags.None).ContinueWith(t => OnReceive(node, t));
                        }
                    }
                }
                catch (OperationCanceledException ex)
                {
                    KillClient(node);
                }
                catch (InvalidOperationException ex)
                {
                    KillClient(node);
                }
                catch (SocketException ex)
                {
                    KillClient(node);
                }
                catch (Exception ex)
                {
                    KillClient(node);
                    _exceptionHandlerDelegate?.Invoke(ex, false, _port);
                }
            }
        }
        /// <summary>
        /// Обработка HTTP запроса от игры на порт 80.
        /// Обрабатывает новостное сообщение, наличие патча, запрос страницы статистики, настройки автоматча и список имен комнат чата.
        /// </summary>
        void OnHttpReceived(TcpPortHandler handler, TcpClientNode node, byte[] buffer, int count)
        {
            try
            {
                var str = buffer.ToUtf8(count);

                LogTrace("HTTP CLIENT HASH " + node.GetHashCode());
                LogTrace("HTTP " + str);

                HttpRequest request;

                using (var ms = new MemoryStream(buffer, 0, count, false, true))
                    request = HttpHelper.GetRequest(ms);

                using (var ms = new MemoryStream())
                {
                    // Запрос страницы статистики по кнопке из игры
                    if (request.Url.StartsWith("/SS_StatsPage", StringComparison.OrdinalIgnoreCase))
                    {
                        HttpHelper.WriteResponse(ms, HttpResponceBuilder.DowstatsRedirect());
                        goto END;
                    }

                    // Запрос текста новостей
                    if (request.Url.EndsWith("news.txt", StringComparison.OrdinalIgnoreCase))
                    {
                        LogForUser($"News requested");

                        // Фикс для рускоязычных
                        if (request.Url.EndsWith("Russiandow_news.txt", StringComparison.OrdinalIgnoreCase))
                        {
                            HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(GameSpyHttpDataConstants.RusNews, Encoding.Unicode));
                        }
                        else
                        {
                            HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(GameSpyHttpDataConstants.EnNews, Encoding.Unicode));
                        }
                        goto END;
                    }

                    // Отправка сообщения дня. Вроде нигде не отображается
                    if (request.Url.StartsWith("/motd/motd", StringComparison.OrdinalIgnoreCase))
                    {
                        HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(GameSpyHttpDataConstants.RusNews, Encoding.Unicode));
                        goto END;
                    }

                    // Проверка на существование патча. Можно прокидывать свои патчи для игры
                    if (request.Url.StartsWith("/motd/vercheck", StringComparison.OrdinalIgnoreCase))
                    {
                        LogForUser($"Vercheck requested");

                        // Пример отправки ссылки на скачивания патча
                        //HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(@"\newver\1\newvername\1.4\dlurl\http://127.0.0.1/NewPatchHere.exe"));

                        // Отправка инфы о том, что патча сейчас нет
                        HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(@"\newver\0", Encoding.UTF8));
                        goto END;
                    }

                    // Запрос списка комнат с именами для отображения в интерфейсе
                    if (request.Url.EndsWith("LobbyRooms.lua", StringComparison.OrdinalIgnoreCase))
                    {
                        LogForUser($"LobbyRooms requested");
                        HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(GameSpyHttpDataConstants.RoomPairs, Encoding.ASCII));
                        goto END;
                    }

                    // Запрос дефолных настроек автоматча
                    if (request.Url.EndsWith("AutomatchDefaultsSS.lua", StringComparison.OrdinalIgnoreCase) || request.Url.EndsWith("AutomatchDefaultsDXP2Fixed.lua", StringComparison.OrdinalIgnoreCase))
                    {
                        LogForUser($"AutomatchDefaults requested");
                        //HttpHelper.WriteResponse(ms, HttpResponceBuilder.TextFileBytes(CoreContext.MasterServer.AutomatchDefaultsBytes));
                        HttpHelper.WriteResponse(ms, HttpResponceBuilder.Text(GameSpyHttpDataConstants.AutomatchDefaults, Encoding.ASCII));
                        goto END;
                    }

                    /*if (request.Url.EndsWith("homepage.php.htm", StringComparison.OrdinalIgnoreCase))
                     * {
                     *  if (StatsResponce == null || (DateTime.Now - _lastStatsUpdate).TotalMinutes > 5)
                     *      StatsResponce = BuildTop10StatsResponce();
                     *
                     *  HttpHelper.WriteResponse(ms, StatsResponce);
                     *  goto END;
                     * }*/

                    // Если дошли сюда - отправляет NotFound
                    HttpHelper.WriteResponse(ms, HttpResponceBuilder.NotFound());

END:
                    LogTrace("HTTP WANT TO SEND " + node.GetHashCode() + " " + ms.Length);
                    handler.Send(node, ms.ToArray());
                    handler.KillClient(node);
                }
            }
            catch (InvalidDataException ex)
            {
                //Log(ex);
            }
        }
 public bool SendAskii(TcpClientNode node, string message)
 {
     return(Send(node, message.ToAsciiBytes()));
 }
 public bool SendUtf8(TcpClientNode node, string message)
 {
     return(Send(node, message.ToUTF8Bytes()));
 }
Esempio n. 10
0
        /// <summary>
        /// Обрабатывает одно сообщение сервера
        /// </summary>
        private void HandleClientManagerMessage(TcpPortHandler handler, TcpClientNode node, string mes)
        {
            LogTrace("CLIENT " + mes);
            var pairs = ParseHelper.ParseMessage(mes, out string query);

            if (pairs == null || string.IsNullOrWhiteSpace(query))
            {
                return;
            }

            // Исправление бага, когда игра по какой-то причине соединяет логин и почту в одну строку. Разбиваем, иначе не будет работать алгоритм хэширования при логине
            if (pairs.ContainsKey("name") && !pairs.ContainsKey("email"))
            {
                var parts = pairs["name"].Split('@');

                if (parts.Length > 2)
                {
                    pairs["name"]  = parts[0];
                    pairs["email"] = parts[1] + "@" + parts[2];
                }
            }

            switch (query)
            {
            case "login":
                HandleLogin(node, pairs);
                RestartUserSessionTimer(node);
                break;

            case "logout":
                _emulationAdapter.LeaveFromCurrentLobby();
                _emulationAdapter.OnLogout();
                break;

            case "registernick":
                handler.SendAskii(node, string.Format(@"\rn\{0}\id\{1}\final\", pairs["uniquenick"], pairs["id"]));
                break;

            case "ka":
                handler.SendAskii(node, $@"\ka\\final\");
                break;

            case "status":
                HandleStatus(node, pairs);
                break;

            case "newuser":
            {
                var nick     = pairs["nick"];
                var email    = pairs["email"];
                var password = GSUtils.DecryptPassword(pairs["passwordenc"]);
                var passHash = password.ToMD5();

                _emulationAdapter.TryCreateProfile(nick, email, passHash);
            }
            break;

            case "getprofile":
                // TODO
                break;

            default:
                Debugger.Break();
                break;
            }
        }
Esempio n. 11
0
 /// <summary>
 /// Обрабатывает входящие TCP соединения для сервера LOGIN (Client)
 /// </summary>
 void OnClientAccept(TcpPortHandler handler, TcpClientNode node, CancellationToken token)
 {
     //Обновляем челендж для нового соединения
     _serverChallenge = RandomHelper.GetString(10);
     handler.SendAskii(node, $@"\lc\1\challenge\{_serverChallenge}\id\1\final\");
 }
Esempio n. 12
0
        void OnSearchManagerReceived(TcpPortHandler handler, TcpClientNode node, byte[] buffer, int count)
        {
            var str   = buffer.ToUtf8(count);
            var pairs = ParseHelper.ParseMessage(str, out string query);


            switch (query)
            {
            case "nicks":
            {
                // \\nicks\\\\email\\[email protected]\\passenc\\J4PGhRi[\\namespaceid\\7\\partnerid\\0\\gamename\\whamdowfr\\final\\

                if (!pairs.ContainsKey("email") || (!pairs.ContainsKey("passenc") && !pairs.ContainsKey("pass")))
                {
                    handler.SendAskii(node, @"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                    return;
                }

                // Чей-то тестовый код

                /*
                 * string password = String.Empty;
                 * if (pairs.ContainsKey("passenc"))
                 * {
                 *  password = GSUtils.DecryptPassword(pairs["passenc"]);
                 * }
                 * else if (pairs.ContainsKey("pass"))
                 * {
                 *  password = pairs["pass"];
                 * }
                 *
                 * password = password.ToMD5();*/

                _emulationAdapter.RequestAllUserNicks(pairs["email"]);
                return;
            }

            case "check":
            {
                string name = String.Empty;

                if (String.IsNullOrWhiteSpace(name))
                {
                    if (pairs.ContainsKey("uniquenick"))
                    {
                        name = pairs["uniquenick"];
                    }
                }
                if (String.IsNullOrWhiteSpace(name))
                {
                    if (pairs.ContainsKey("nick"))
                    {
                        name = pairs["nick"];
                    }
                }

                if (String.IsNullOrWhiteSpace(name))
                {
                    handler.SendAskii(node, @"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                    return;
                }

                _emulationAdapter.RequestNameCheck(name);
                return;
            }

            default:
                break;
            }

            Debugger.Break();
        }