예제 #1
0
        /// <summary>
        /// Sends a request to obtains a list of lobbies matching the specified criteria.
        /// </summary>
        /// <param name="appId">The ID of app for which we're requesting a list of lobbies.</param>
        /// <param name="filters">An optional list of filters.</param>
        /// <param name="maxLobbies">An optional maximum number of lobbies that will be returned.</param>
        /// <returns><c>null</c>, if the request could not be submitted i.e. not yet logged in. Otherwise, an <see cref="AsyncJob{GetLobbyListCallback}"/>.</returns>
        public AsyncJob <GetLobbyListCallback> GetLobbyList(uint appId, List <Lobby.Filter> filters = null, int maxLobbies = -1)
        {
            if (Client.CellID == null)
            {
                return(null);
            }

            var getLobbies = new ClientMsgProtobuf <CMsgClientMMSGetLobbyList>(EMsg.ClientMMSGetLobbyList)
            {
                Body =
                {
                    app_id                = appId,
                    cell_id               = Client.CellID.Value,
                    public_ip             = NetHelpers.GetIPAddress(Client.PublicIP),
                    num_lobbies_requested = maxLobbies
                },
                SourceJobID = Client.GetNextJobID()
            };

            if (filters != null)
            {
                foreach (var filter in filters)
                {
                    getLobbies.Body.filters.Add(filter.Serialize());
                }
            }

            Send(getLobbies, appId);

            return(new AsyncJob <GetLobbyListCallback>(Client, getLobbies.SourceJobID));
        }
예제 #2
0
        /// <summary>
        /// Opens a storage session with the storage server.
        /// </summary>
        /// <param name="depotId">The depot id.</param>
        /// <param name="depotVersion">The depot version.</param>
        /// <param name="cellId">The cell id.</param>
        /// <param name="credentials">The credentials.</param>
        /// <returns>A new StorageSession object for the session.</returns>
        public StorageSession OpenStorage(uint depotId, uint depotVersion, uint cellId, Credentials credentials)
        {
            bool bRet = this.HandshakeServer(( ESteam2ServerType )7);

            if (!bRet)
            {
                throw new Steam2Exception("Storage handshake with content server failed");
            }

            bRet = this.SendCommand(
                0, // open storage
                cellId
                );

            byte success = this.Socket.Reader.ReadByte();

            if (success == 0)
            {
                throw new Steam2Exception(string.Format("Unable to open storage depot for cellid {0}", cellId));
            }

            ushort bannerLen = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt16());

            byte[] bannerData = this.Socket.Reader.ReadBytes(bannerLen);

            return(new StorageSession(this, depotId, depotVersion, credentials));
        }
예제 #3
0
            internal CMListCallback(CMsgClientCMList cmMsg)
            {
                var cmList = cmMsg.cm_addresses
                             .Zip(cmMsg.cm_ports, (addr, port) => new IPEndPoint(NetHelpers.GetIPAddress(addr), ( int )port));

                Servers = new ReadOnlyCollection <IPEndPoint>(cmList.ToList());
            }
예제 #4
0
            internal LoggedOnCallback(CMsgClientLogonResponse resp)
            {
                this.Result         = ( EResult )resp.eresult;
                this.ExtendedResult = ( EResult )resp.eresult_extended;

                this.OutOfGameSecsPerHeartbeat = resp.out_of_game_heartbeat_seconds;
                this.InGameSecsPerHeartbeat    = resp.in_game_heartbeat_seconds;

                this.PublicIP = NetHelpers.GetIPAddress(resp.public_ip);

                this.ServerTime = DateUtils.DateTimeFromUnixTime(resp.rtime32_server_time);

                this.AccountFlags = ( EAccountFlags )resp.account_flags;

                this.ClientSteamID = new SteamID(resp.client_supplied_steamid);

                this.EmailDomain = resp.email_domain;

                this.CellID = resp.cell_id;
                this.CellIDPingThreshold = resp.cell_id_ping_threshold;

                this.Steam2Ticket = resp.steam2_ticket;

                this.IPCountryCode = resp.ip_country_code;

                this.WebAPIUserNonce = resp.webapi_authenticate_user_nonce;

                this.UsePICS = resp.use_pics;

                this.VanityURL = resp.vanity_url;

                this.NumLoginFailuresToMigrate = resp.count_loginfailures_to_migrate;
                this.NumDisconnectsToMigrate   = resp.count_disconnects_to_migrate;
            }
예제 #5
0
        /// <summary>
        /// Requests a list of servers from the Steam game master server.
        /// Results are returned in a <see cref="QueryCallback"/>.
        /// The returned <see cref="AsyncJob{T}"/> can also be awaited to retrieve the callback result.
        /// </summary>
        /// <param name="details">The details for the request.</param>
        /// <returns>The Job ID of the request. This can be used to find the appropriate <see cref="QueryCallback"/>.</returns>
        public AsyncJob <QueryCallback> ServerQuery(QueryDetails details)
        {
            if (details == null)
            {
                throw new ArgumentNullException(nameof(details));
            }

            var query = new ClientMsgProtobuf <CMsgClientGMSServerQuery>(EMsg.ClientGMSServerQuery);

            query.SourceJobID = Client.GetNextJobID();

            query.Body.app_id = details.AppID;

            if (details.GeoLocatedIP != null)
            {
                query.Body.geo_location_ip = NetHelpers.GetIPAddressAsUInt(details.GeoLocatedIP);
            }

            query.Body.filter_text = details.Filter;
            query.Body.region_code = ( uint )details.Region;

            query.Body.max_servers = details.MaxServers;

            this.Client.Send(query);

            return(new AsyncJob <QueryCallback>(this.Client, query.SourceJobID));
        }
예제 #6
0
        /// <summary>
        /// Sends the server's status to the Steam network.
        /// Results are returned in a <see cref="StatusReplyCallback"/> callback.
        /// </summary>
        /// <param name="details">A <see cref="SteamGameServer.StatusDetails"/> object containing the server's status.</param>
        public void SendStatus(StatusDetails details)
        {
            if (details == null)
            {
                throw new ArgumentNullException(nameof(details));
            }

            if (details.Address != null && details.Address.AddressFamily != AddressFamily.InterNetwork)
            {
                throw new ArgumentException("Only IPv4 addresses are supported.");
            }

            var status = new ClientMsgProtobuf <CMsgGSServerType>(EMsg.GSServerType);

            status.Body.app_id_served   = details.AppID;
            status.Body.flags           = (uint)details.ServerFlags;
            status.Body.game_dir        = details.GameDirectory;
            status.Body.game_port       = details.Port;
            status.Body.game_query_port = details.QueryPort;
            status.Body.game_version    = details.Version;

            if (details.Address != null)
            {
                status.Body.game_ip_address = NetHelpers.GetIPAddress(details.Address);
            }

            this.Client.Send(status);
        }
예제 #7
0
        /// <summary>
        /// Logs the client into the Steam3 network as an anonymous game server.
        /// The client should already have been connected at this point.
        /// Results are returned in a <see cref="SteamUser.LoggedOnCallback"/>.
        /// </summary>
        /// <param name="appId">The AppID served by this game server, or 0 for the default.</param>
        public void LogOnAnonymous(uint appId = 0)
        {
            if (!this.Client.IsConnected)
            {
                this.Client.PostCallback(new SteamUser.LoggedOnCallback(EResult.NoConnection));
                return;
            }

            var logon = new ClientMsgProtobuf <CMsgClientLogon>(EMsg.ClientLogon);

            SteamID gsId = new SteamID(0, 0, Client.Universe, EAccountType.AnonGameServer);

            logon.ProtoHeader.client_sessionid = 0;
            logon.ProtoHeader.steamid          = gsId.ConvertToUInt64();

            uint localIp = NetHelpers.GetIPAddress(this.Client.LocalIP);

            logon.Body.obfustucated_private_ip = localIp ^ MsgClientLogon.ObfuscationMask;

            logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;

            logon.Body.client_os_type     = ( uint )Utils.GetOSType();
            logon.Body.game_server_app_id = ( int )appId;
            logon.Body.machine_id         = HardwareUtils.GetMachineID();

            this.Client.Send(logon);
        }
예제 #8
0
        /// <summary>
        /// Requests the cell ID of the currently connected content server.
        /// </summary>
        /// <returns>The cell ID of the server.</returns>
        public uint GetCellID()
        {
            if (!this.HandshakeServer(( ESteam2ServerType )3))
            {
                throw new Steam2Exception("Package handshake with content server failed");
            }

            TcpPacket packet = new TcpPacket();

            packet.Write(( uint )2);


            try
            {
                this.Socket.Send(packet);

                uint cellId = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                return(cellId);
            }
            catch (Exception ex)
            {
                throw new Steam2Exception("Unable to request cell id", ex);
            }
        }
예제 #9
0
            internal LoggedOnCallback(CMsgClientLogonResponse resp)
#endif
            {
                this.Result         = ( EResult )resp.eresult;
                this.ExtendedResult = ( EResult )resp.eresult_extended;

                this.OutOfGameSecsPerHeartbeat = resp.out_of_game_heartbeat_seconds;
                this.InGameSecsPerHeartbeat    = resp.in_game_heartbeat_seconds;

                this.PublicIP = NetHelpers.GetIPAddress(resp.public_ip);

                this.ServerTime = Utils.DateTimeFromUnixTime(resp.rtime32_server_time);

                this.AccountFlags = ( EAccountFlags )resp.account_flags;

                this.ClientSteamID = new SteamID(resp.client_supplied_steamid);

                this.EmailDomain = resp.email_domain;

                this.CellID = resp.cell_id;

                if (resp.steam2_ticket != null)
                {
                    this.Steam2Ticket = new Steam2Ticket(resp.steam2_ticket);
                }
            }
예제 #10
0
            internal PersonaStateCallback(CMsgClientPersonaState.Friend friend)
#endif
            {
                this.StatusFlags = ( EClientPersonaStateFlag )friend.persona_state_flags;

                this.FriendID = friend.friendid;
                this.State    = ( EPersonaState )friend.persona_state;

                this.GameAppID = friend.game_played_app_id;
                this.GameID    = friend.gameid;
                this.GameName  = friend.game_name;

                this.GameServerIP   = NetHelpers.GetIPAddress(friend.game_server_ip);
                this.GameServerPort = friend.game_server_port;
                this.QueryPort      = friend.query_port;

                this.SourceSteamID = friend.steamid_source;

                this.GameDataBlob = friend.game_data_blob;

                this.Name = friend.player_name;

                this.AvatarHash = friend.avatar_hash;

                this.LastLogOff = Utils.DateTimeFromUnixTime(friend.last_logoff);
                this.LastLogOn  = Utils.DateTimeFromUnixTime(friend.last_logon);

                this.ClanRank = friend.clan_rank;
                this.ClanTag  = friend.clan_tag;

                this.OnlineSessionInstances = friend.online_session_instances;
                this.PublishedSessionID     = friend.published_instance_id;
            }
예제 #11
0
        /// <summary>
        /// Sends a request to create a new lobby.
        /// </summary>
        /// <param name="appId">ID of the app the lobby will belong to.</param>
        /// <param name="lobbyType">The new lobby type.</param>
        /// <param name="maxMembers">The new maximum number of members that may occupy the lobby.</param>
        /// <param name="lobbyFlags">The new lobby flags. Defaults to 0.</param>
        /// <param name="metadata">The new metadata for the lobby. Defaults to <c>null</c> (treated as an empty dictionary).</param>
        /// <returns><c>null</c>, if the request could not be submitted i.e. not yet logged in. Otherwise, an <see cref="AsyncJob{CreateLobbyCallback}"/>.</returns>
        public AsyncJob <CreateLobbyCallback> CreateLobby(uint appId, ELobbyType lobbyType, int maxMembers, int lobbyFlags = 0,
                                                          IReadOnlyDictionary <string, string> metadata = null)
        {
            if (Client.CellID == null)
            {
                return(null);
            }

            var personaName = Client.GetHandler <SteamFriends>().GetPersonaName();

            var createLobby = new ClientMsgProtobuf <CMsgClientMMSCreateLobby>(EMsg.ClientMMSCreateLobby)
            {
                Body =
                {
                    app_id             = appId,
                    lobby_type         = ( int )lobbyType,
                    max_members        = maxMembers,
                    lobby_flags        = lobbyFlags,
                    metadata           = Lobby.EncodeMetadata(metadata),
                    cell_id            = Client.CellID.Value,
                    public_ip          = NetHelpers.GetIPAddress(Client.PublicIP),
                    persona_name_owner = personaName
                },
                SourceJobID = Client.GetNextJobID()
            };

            Send(createLobby, appId);

            lobbyManipulationRequests[createLobby.SourceJobID] = createLobby.Body;
            return(AttachIncompleteManipulationHandler(new AsyncJob <CreateLobbyCallback>(Client, createLobby.SourceJobID)));
        }
예제 #12
0
        /// <summary>
        /// Logs onto the Steam network as a persistent game server.
        /// The client should already have been connected at this point.
        /// Results are return in a <see cref="SteamUser.LoggedOnCallback"/>.
        /// </summary>
        /// <param name="details">The details to use for logging on.</param>
        /// <exception cref="ArgumentNullException">No logon details were provided.</exception>
        /// <exception cref="ArgumentException">Username or password are not set within <paramref name="details"/>.</exception>
        public void LogOn(LogOnDetails details)
        {
            if (details == null)
            {
                throw new ArgumentNullException("details");
            }

            if (string.IsNullOrEmpty(details.Username) || string.IsNullOrEmpty(details.Password))
            {
                throw new ArgumentException("LogOn requires a username and password to be set in 'details'.");
            }

            var logon = new ClientMsgProtobuf <CMsgClientLogon>(EMsg.ClientLogon);

            SteamID gsId = new SteamID(0, 0, Client.ConnectedUniverse, EAccountType.GameServer);

            logon.ProtoHeader.client_sessionid = 0;
            logon.ProtoHeader.steamid          = gsId.ConvertToUInt64();

            uint localIp = NetHelpers.GetIPAddress(this.Client.LocalIP);

            logon.Body.obfustucated_private_ip = localIp ^ MsgClientLogon.ObfuscationMask;

            logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;

            logon.Body.client_os_type     = ( uint )Utils.GetOSType();
            logon.Body.game_server_app_id = ( int )details.AppID;
            logon.Body.machine_id         = Utils.GenerateMachineID();

            logon.Body.account_name = details.Username;
            logon.Body.password     = details.Password;

            this.Client.Send(logon);
        }
예제 #13
0
                internal Server(CMsgGMSClientServerQueryResponse.Server server)
                {
                    EndPoint = new IPEndPoint(
                        NetHelpers.GetIPAddress(server.server_ip),
                        ( int )server.server_port);

                    AuthedPlayers = server.auth_players;
                }
예제 #14
0
            internal StorageSession(ContentServerClient cli, uint depotId, uint depotVersion, Credentials credentials)
            {
                this.DepotID      = depotId;
                this.DepotVersion = depotVersion;

                this.client = cli;


                bool bRet = false;

                if (credentials == null)
                {
                    bRet = this.SendCommand(
                        9, // open storage
                        ConnectionID,
                        MessageID,
                        depotId,
                        depotVersion
                        );
                }
                else
                {
                    byte[] serverTgt = credentials.Steam2Ticket.Entries[14].Data;   // god help this never change

                    bRet = this.SendCommand(
                        10, // open storage with login
                        ConnectionID,
                        MessageID,
                        depotId,
                        depotVersion,
                        ( ushort )serverTgt.Length,
                        serverTgt,
                        NetHelpers.EndianSwap(credentials.SessionToken),
                        ( byte )credentials.AppTicket.Length,
                        credentials.AppTicket
                        );
                }

                // the server sends us back the connection and message ids
                // the client probably performs a sanity check?
                uint connId = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                uint msgId  = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                byte hasDepot = this.Socket.Reader.ReadByte();

                // the server gives us 0x1 if the depot doesn't exist or requires authentication
                if (hasDepot != 0)
                {
                    throw new Steam2Exception("Content server does not have depot, or valid credentials were not given");
                }

                StorageID = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                uint storageChecksum = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                this.ConnectionID++;
            }
예제 #15
0
        /// <summary>
        /// Logs the client into the Steam3 network.
        /// The client should already have been connected at this point.
        /// Results are returned in a <see cref="LoggedOnCallback"/>.
        /// </summary>
        /// <param name="details">The details to use for logging on.</param>
        /// <exception cref="ArgumentNullException">No logon details were provided.</exception>
        /// <exception cref="ArgumentException">Username or password are not set within <paramref name="details"/>.</exception>
        public void LogOn(LogOnDetails details)
        {
            if (details == null)
            {
                throw new ArgumentNullException("details");
            }
            if (string.IsNullOrEmpty(details.Username) || string.IsNullOrEmpty(details.Password))
            {
                throw new ArgumentException("LogOn requires a username and password to be set in 'details'.");
            }
            if (!this.Client.IsConnected)
            {
                this.Client.PostCallback(new LoggedOnCallback(EResult.NoConnection));
                return;
            }

            var logon = new ClientMsgProtobuf <CMsgClientLogon>(EMsg.ClientLogon);

            SteamID steamId = new SteamID(details.AccountID, details.AccountInstance, Client.ConnectedUniverse, EAccountType.Individual);

            uint localIp = NetHelpers.GetIPAddress(this.Client.LocalIP);

            logon.ProtoHeader.client_sessionid = 0;
            logon.ProtoHeader.steamid          = steamId.ConvertToUInt64();

            logon.Body.obfustucated_private_ip = localIp ^ MsgClientLogon.ObfuscationMask;

            logon.Body.account_name = details.Username;
            logon.Body.password     = details.Password;

            logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;
            logon.Body.client_os_type   = ( uint )Utils.GetOSType();
            logon.Body.client_language  = "english";

            logon.Body.steam2_ticket_request = details.RequestSteam2Ticket;

            // we're now using the latest steamclient package version, this is required to get a proper sentry file for steam guard
            logon.Body.client_package_version = 1771; // todo: determine if this is still required

            // this is not a proper machine id that Steam accepts
            // but it's good enough for identifying a machine
            logon.Body.machine_id = Utils.GenerateMachineID();


            // steam guard
            logon.Body.auth_code       = details.AuthCode;
            logon.Body.two_factor_code = details.TwoFactorCode;

            logon.Body.sha_sentryfile     = details.SentryFileHash;
            logon.Body.eresult_sentryfile = ( int )(details.SentryFileHash != null ? EResult.OK : EResult.FileNotFound);


            this.Client.Send(logon);
        }
예제 #16
0
        /// <summary>
        /// Attempts to receive a tcp packet from the socket.
        /// </summary>
        /// <returns>The packet.</returns>
        public TcpPacket ReceivePacket()
        {
            TcpPacket pack = new TcpPacket();

            uint size = NetHelpers.EndianSwap(this.Reader.ReadUInt32());

            byte[] payload = Reader.ReadBytes(( int )size);

            pack.SetPayload(payload);

            return(pack);
        }
예제 #17
0
 /// <summary>
 /// Performs a handshake with the server.
 /// </summary>
 /// <param name="type">The expected server type the client is handshaking with.</param>
 /// <returns>True if the handshake succeeded; otherwise false.</returns>
 protected bool HandshakeServer(ESteam2ServerType type)
 {
     try
     {
         Socket.Writer.Write(NetHelpers.EndianSwap(( uint )type));
         return(Socket.Reader.ReadByte() == 1);
     }
     catch
     {
         return(false);
     }
 }
예제 #18
0
        /// <summary>
        /// Gets the local IP.
        /// </summary>
        /// <returns>The local IP.</returns>
        public override IPAddress GetLocalIP()
        {
            netLock.EnterReadLock();

            try
            {
                return(NetHelpers.GetLocalIP(sock));
            }
            finally
            {
                netLock.ExitReadLock();
            }
        }
예제 #19
0
            internal LoggedOnCallback(MsgClientLogOnResponse resp)
            {
                this.Result = resp.Result;

                this.OutOfGameSecsPerHeartbeat = resp.OutOfGameHeartbeatRateSec;
                this.InGameSecsPerHeartbeat    = resp.InGameHeartbeatRateSec;

                this.PublicIP = NetHelpers.GetIPAddress(resp.IpPublic);

                this.ServerTime = DateUtils.DateTimeFromUnixTime(resp.ServerRealTime);

                this.ClientSteamID = resp.ClientSuppliedSteamId;
            }
예제 #20
0
        /// <summary>
        /// Load a list of servers from the Steam Directory.
        /// </summary>
        /// <param name="configuration">Configuration Object</param>
        /// <param name="cancellationToken">Cancellation Token</param>
        /// <returns>A <see cref="System.Threading.Tasks.Task"/> with the Result set to an enumerable list of <see cref="ServerRecord"/>s.</returns>
        public static Task <IReadOnlyCollection <ServerRecord> > LoadAsync(SteamConfiguration configuration, CancellationToken cancellationToken)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            var directory = configuration.GetAsyncWebAPIInterface("ISteamDirectory");
            var args      = new Dictionary <string, string>
            {
                ["cellid"] = configuration.CellID.ToString(CultureInfo.InvariantCulture)
            };

            cancellationToken.ThrowIfCancellationRequested();

            var task = directory.CallAsync(HttpMethod.Get, "GetCMList", version: 1, args: args);

            return(task.ContinueWith(t =>
            {
                var response = task.Result;
                var result = ( EResult )response["result"].AsInteger(( int )EResult.Invalid);
                if (result != EResult.OK)
                {
                    throw new InvalidOperationException(string.Format("Steam Web API returned EResult.{0}", result));
                }

                var socketList = response["serverlist"];
                var websocketList = response["serverlist_websockets"];

                cancellationToken.ThrowIfCancellationRequested();

                var serverRecords = new List <ServerRecord>(capacity: socketList.Children.Count + websocketList.Children.Count);

                foreach (var child in socketList.Children)
                {
                    if (!NetHelpers.TryParseIPEndPoint(child.Value, out var endpoint))
                    {
                        continue;
                    }

                    serverRecords.Add(ServerRecord.CreateSocketServer(endpoint));
                }

                foreach (var child in websocketList.Children)
                {
                    serverRecords.Add(ServerRecord.CreateWebSocketServer(child.Value));
                }

                return (IReadOnlyCollection <ServerRecord>)serverRecords;
            }, cancellationToken, TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.NotOnFaulted, TaskScheduler.Current));
        }
예제 #21
0
            /// <summary>
            /// Downloads the <see cref="Steam2Manifest"/> which contains metadata representing the files within the depot.
            /// </summary>
            /// <returns></returns>
            public Steam2Manifest DownloadManifest()
            {
                bool bRet = this.SendCommand(
                    4, // download manifest
                    this.StorageID,
                    this.MessageID
                    );


                uint storId = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                uint msgId  = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                // name is a guess
                byte hasManifest = this.Socket.Reader.ReadByte();

                uint manifestLength = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                byte[] manifest = new byte[manifestLength];

                uint manifestChunksToRead = manifestLength;

                do
                {
                    uint chunkStorID = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                    uint chunkMsgID  = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                    uint chunkLen    = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                    chunkLen = Math.Min(chunkLen, manifestChunksToRead);
                    uint toRead = chunkLen;

                    while (toRead > 0)
                    {
                        uint socketRead = ( uint )this.Socket.Reader.Read(manifest, ( int )((manifestLength - manifestChunksToRead) + (chunkLen - toRead)), ( int )toRead);
                        toRead = toRead - socketRead;
                    }

                    manifestChunksToRead = manifestChunksToRead - chunkLen;
                } while (manifestChunksToRead > 0);

                this.MessageID++;

                return(new Steam2Manifest(manifest));
            }
예제 #22
0
            /// <summary>
            /// Downloads the <see cref="Steam2ChecksumData"/> for this depot.
            /// </summary>
            /// <returns></returns>
            public Steam2ChecksumData DownloadChecksums()
            {
                bool bRet = this.SendCommand(
                    6, // download checksums
                    this.StorageID,
                    this.MessageID
                    );

                uint storId = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                uint msgId  = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                // name is a(n incorrect) guess
                byte hasChecksums = this.Socket.Reader.ReadByte();

                uint checksumsLength = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                byte[] checksumData = new byte[checksumsLength];

                uint checksumChunksToRead = checksumsLength;

                do
                {
                    uint chunkStorID = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                    uint chunkMsgID  = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                    uint chunkLen    = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                    chunkLen = Math.Min(chunkLen, checksumChunksToRead);
                    uint toRead = chunkLen;

                    while (toRead > 0)
                    {
                        uint socketRead = ( uint )this.Socket.Reader.Read(checksumData, ( int )((checksumsLength - checksumChunksToRead) + (chunkLen - toRead)), ( int )toRead);
                        toRead = toRead - socketRead;
                    }

                    checksumChunksToRead = checksumChunksToRead - chunkLen;
                } while (checksumChunksToRead > 0);

                this.MessageID++;

                return(new Steam2ChecksumData(checksumData));
            }
예제 #23
0
        public override IPAddress GetLocalIP()
        {
            lock (netLock)
            {
                if (socket == null)
                {
                    return(IPAddress.None);
                }

                try
                {
                    return(NetHelpers.GetLocalIP(socket));
                }
                catch (Exception ex)
                {
                    DebugLog.WriteLine("TcpConnection", "Socket exception trying to read bound IP: {0}", ex);
                    return(IPAddress.None);
                }
            }
        }
예제 #24
0
        public IPAddress GetLocalIP()
        {
            lock (netLock)
            {
                if (socket == null)
                {
                    return(IPAddress.None);
                }

                try
                {
                    return(NetHelpers.GetLocalIP(socket));
                }
                catch (Exception ex)
                {
                    log.LogDebug(nameof(TcpConnection), "Socket exception trying to read bound IP: {0}", ex);
                    return(IPAddress.None);
                }
            }
        }
예제 #25
0
            /// <summary>
            /// Downloads the specified package file.
            /// </summary>
            /// <param name="fileName">Name of the file.</param>
            /// <returns>A byte array representing the file.</returns>
            public byte[] DownloadPackage(string fileName)
            {
                TcpPacket packet = new TcpPacket();

                packet.Write(( uint )0);   // unknown, always 0?
                packet.Write(( uint )0);   // unknown, always 0?
                packet.Write(( uint )fileName.Length);
                packet.Write(fileName);
                packet.Write(this.CellID);

                this.Socket.Send(packet);

                // length is sent twice, as two uints
                uint len1 = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());
                uint len2 = NetHelpers.EndianSwap(this.Socket.Reader.ReadUInt32());

                byte[] packageData = this.Socket.Reader.ReadBytes(( int )len1);

                return(packageData);
            }
예제 #26
0
        /// <summary>
        /// Load a list of servers from the Steam Directory.
        /// </summary>
        /// <param name="cellid">Cell ID</param>
        /// <param name="cancellationToken">Cancellation Token</param>
        /// <returns>A <see cref="System.Threading.Tasks.Task"/> with the Result set to an enumerable list of <see cref="System.Net.IPEndPoint"/>s.</returns>
        public static Task <IEnumerable <IPEndPoint> > LoadAsync(uint cellid, CancellationToken cancellationToken)
        {
            var directory = new WebAPI.AsyncInterface("ISteamDirectory", null);
            var args      = new Dictionary <string, string>
            {
                { "cellid", cellid.ToString() }
            };

            cancellationToken.ThrowIfCancellationRequested();

            var task = directory.CallAsync(HttpMethod.Get, "GetCMList", version: 1, args: args, secure: true);

            return(task.ContinueWith(t =>
            {
                var response = task.Result;
                var result = ( EResult )response["result"].AsInteger(( int )EResult.Invalid);
                if (result != EResult.OK)
                {
                    throw new InvalidOperationException(string.Format("Steam Web API returned EResult.{0}", result));
                }

                var list = response["serverlist"];

                cancellationToken.ThrowIfCancellationRequested();

                var endPoints = new List <IPEndPoint>(capacity: list.Children.Count);

                foreach (var child in list.Children)
                {
                    IPEndPoint endpoint;
                    if (!NetHelpers.TryParseIPEndPoint(child.Value, out endpoint))
                    {
                        continue;
                    }

                    endPoints.Add(endpoint);
                }

                return endPoints.AsEnumerable();
            }, cancellationToken, TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.NotOnFaulted, TaskScheduler.Current));
        }
예제 #27
0
        /// <summary>
        /// Logs the client into the Steam3 network as an anonymous game server.
        /// The client should already have been connected at this point.
        /// Results are returned in a <see cref="SteamUser.LoggedOnCallback"/>.
        /// </summary>
        /// <param name="appId">The AppID served by this game server, or 0 for the default.</param>
        public void LogOnAnonymous(uint appId = 0)
        {
            var logon = new ClientMsgProtobuf <CMsgClientLogon>(EMsg.ClientLogon);

            SteamID gsId = new SteamID(0, 0, Client.ConnectedUniverse, EAccountType.AnonGameServer);

            logon.ProtoHeader.client_sessionid = 0;
            logon.ProtoHeader.steamid          = gsId.ConvertToUInt64();

            uint localIp = NetHelpers.GetIPAddress(this.Client.LocalIP);

            logon.Body.obfustucated_private_ip = localIp ^ MsgClientLogon.ObfuscationMask;

            logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;

            logon.Body.client_os_type     = ( uint )Utils.GetOSType();
            logon.Body.game_server_app_id = ( int )appId;
            logon.Body.machine_id         = Utils.GenerateMachineID();

            this.Client.Send(logon);
        }
예제 #28
0
        /// <summary>
        /// Logs onto the Steam network as a persistent game server.
        /// The client should already have been connected at this point.
        /// Results are return in a <see cref="SteamUser.LoggedOnCallback"/>.
        /// </summary>
        /// <param name="details">The details to use for logging on.</param>
        /// <exception cref="System.ArgumentNullException">No logon details were provided.</exception>
        /// <exception cref="System.ArgumentException">Username or password are not set within <paramref name="details"/>.</exception>
        public void LogOn(LogOnDetails details)
        {
            if (details == null)
            {
                throw new ArgumentNullException("details");
            }

            if (string.IsNullOrEmpty(details.Token))
            {
                throw new ArgumentException("LogOn requires a game server token to be set in 'details'.");
            }

            if (!this.Client.IsConnected)
            {
                this.Client.PostCallback(new SteamUser.LoggedOnCallback(EResult.NoConnection));
                return;
            }

            var logon = new ClientMsgProtobuf <CMsgClientLogon>(EMsg.ClientLogonGameServer);

            SteamID gsId = new SteamID(0, 0, Client.Universe, EAccountType.GameServer);

            logon.ProtoHeader.client_sessionid = 0;
            logon.ProtoHeader.steamid          = gsId.ConvertToUInt64();

            uint localIp = NetHelpers.GetIPAddress(this.Client.LocalIP);

            logon.Body.obfustucated_private_ip = localIp ^ MsgClientLogon.ObfuscationMask;

            logon.Body.protocol_version = MsgClientLogon.CurrentProtocol;

            logon.Body.client_os_type     = ( uint )Utils.GetOSType();
            logon.Body.game_server_app_id = ( int )details.AppID;
            logon.Body.machine_id         = HardwareUtils.GetMachineID();

            logon.Body.game_server_token = details.Token;

            this.Client.Send(logon);
        }
예제 #29
0
        /// <summary>
        /// Requests a list of servers from the Steam game master server.
        /// Results are returned in a <see cref="QueryCallback"/>.
        /// </summary>
        /// <param name="details">The details for the request.</param>
        /// <returns>The Job ID of the request. This can be used to find the appropriate <see cref="QueryCallback"/>.</returns>
        public JobID ServerQuery(QueryDetails details)
        {
            var query = new ClientMsgProtobuf <CMsgClientGMSServerQuery>(EMsg.ClientGMSServerQuery);

            query.SourceJobID = Client.GetNextJobID();

            query.Body.app_id = details.AppID;

            if (details.GeoLocatedIP != null)
            {
                query.Body.geo_location_ip = NetHelpers.GetIPAddress(details.GeoLocatedIP);
            }

            query.Body.filter_text = details.Filter;
            query.Body.region_code = ( uint )details.Region;

            query.Body.max_servers = details.MaxServers;

            this.Client.Send(query);

            return(query.SourceJobID);
        }
예제 #30
0
        /// <summary>
        /// Gets the local IP.
        /// </summary>
        /// <returns>The local IP.</returns>
        public override IPAddress GetLocalIP()
        {
            while (!wantsNetShutdown && !netLock.TryEnterReadLock(500))
            {
            }

            try
            {
                if (wantsNetShutdown || sock == null)
                {
                    return(null);
                }

                return(NetHelpers.GetLocalIP(sock));
            }
            finally
            {
                if (netLock.IsReadLockHeld)
                {
                    netLock.ExitReadLock();
                }
            }
        }