/// <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)); }
/// <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)); }
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()); }
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; }
/// <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)); }
/// <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); }
/// <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); }
/// <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); } }
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); } }
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; }
/// <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))); }
/// <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); }
internal Server(CMsgGMSClientServerQueryResponse.Server server) { EndPoint = new IPEndPoint( NetHelpers.GetIPAddress(server.server_ip), ( int )server.server_port); AuthedPlayers = server.auth_players; }
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++; }
/// <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); }
/// <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); }
/// <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); } }
/// <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(); } }
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; }
/// <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)); }
/// <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)); }
/// <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)); }
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); } } }
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); } } }
/// <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); }
/// <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)); }
/// <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); }
/// <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); }
/// <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); }
/// <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(); } } }