/// <summary> /// Gets a server list from the Steam master server. /// The callback is invoked from a background thread every time a batch of servers is received. /// The end of the list is marked with an IPEndPoint of 0.0.0.0:0 /// In case of a timeout or an exception, the callback is invoked with a NULL parameter value. /// </summary> /// <exception cref="InvalidOperationException">Thrown if the object is still busy handling a previous call to GetAddresses</exception> public void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter) { ThreadPool.QueueUserWorkItem(x => { var udpSocket = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, ProtocolType.Udp); udpSocket.SendTimeout = 500; udpSocket.ReceiveTimeout = 500; udpSocket.Connect(endPoint); byte[] recvData = new byte[1400]; try { var nextSeed = SeedEndpoint; int totalCount = 0; do { var curSeed = nextSeed; var endpoints = Util.RunWithRetries(() => SendAndReceive(udpSocket, recvData, region, filter, curSeed), this.Retries); ThreadPool.QueueUserWorkItem(y => callback(endpoints)); totalCount += endpoints.Count; nextSeed = endpoints.Last(); } while (!nextSeed.Equals(SeedEndpoint) && totalCount < GetAddressesLimit); } catch (Exception) { callback(null); } finally { try { udpSocket.Close(); } catch { } } }); }
const string SteamWebApiKey = "B7D245299F6F990504A86FF91EC9D6BD"; // create an account and get a steam web api key at http://steamcommunity.com/dev/apikey /// <summary> /// Gets a server list from the Steam master server. /// The callback is invoked from a background thread every time a batch of servers is received. /// The end of the list is marked with an IPEndPoint of 0.0.0.0:0 /// In case of a timeout or an exception, the callback is invoked with a NULL parameter value. /// </summary> /// <exception cref="InvalidOperationException">Thrown if the object is still busy handling a previous call to GetAddresses</exception> public override void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter) { ThreadPool.QueueUserWorkItem(x => { try { using (var cli = new XWebClient()) { var filters = MasterUtil.ProcessFilter(filter); var url = $"https://api.steampowered.com/IGameServersService/GetServerList/v1/?key={SteamWebApiKey}&format=xml&filter={filters}&limit={GetAddressesLimit}"; var xml = cli.DownloadString(url); var ser = new XmlSerializer(typeof(Response)); // replace invalid XML chars ( < 32 ) with char reference var sb = new StringBuilder(xml); for (int i = 0, c = xml.Length; i < c; i++) { if (sb[i] < 32 && !char.IsWhiteSpace(sb[i])) { //{ // sb.Insert(i+1, "#" + ((int)sb[i]).ToString() + ";"); // sb[i] = '&'; //} sb[i] = ' '; } } xml = sb.ToString(); var resp = (Response)ser.Deserialize(new StringReader(xml)); var endpoints = new List <Tuple <IPEndPoint, ServerInfo> >(); foreach (var msg in resp.Servers) { try { int i = msg.addr.IndexOf(':'); if (i > 0) { var info = ConvertToServerInfo(msg); endpoints.Add(new Tuple <IPEndPoint, ServerInfo>(info.EndPoint, info)); } } catch { } } callback(new ReadOnlyCollection <Tuple <IPEndPoint, ServerInfo> >(endpoints), null, false); } } catch (Exception ex) { callback(null, ex, false); } }); }
internal static byte[] BuildPacket(string endPoint, Region region, IpFilter filter) { List<byte> msg = new List<byte>(); msg.Add(Header); msg.Add((byte)region); msg.AddRange(Util.StringToBytes(endPoint)); msg.Add(0x00); if (filter != null) msg.AddRange(Util.StringToBytes(ProcessFilter(filter))); msg.Add(0x00); return msg.ToArray(); }
private static string SubFilter(IpFilter filter, string verb, bool inCascade) { var text = ProcessFilter(filter, true); int count = 0; foreach (var ch in text) { count += ch == '\\' ? 1 : 0; } string prefix = inCascade ? "" : "\\" + verb + "\\" + (count / 2); return(prefix + text.TrimEnd('\0')); }
/// <summary> /// Gets a server list from the Steam master server. /// The callback is invoked from a background thread every time a batch of servers is received. /// The end of the list is marked with an IPEndPoint of 0.0.0.0:0 /// In case of a timeout or an exception, the callback is invoked with a NULL parameter value. /// </summary> /// <exception cref="InvalidOperationException">Thrown if the object is still busy handling a previous call to GetAddresses</exception> public override void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter) { ThreadPool.QueueUserWorkItem(x => { var udpSocket = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, ProtocolType.Udp); udpSocket.SendTimeout = 500; udpSocket.ReceiveTimeout = 500; udpSocket.Connect(endPoint); byte[] recvData = new byte[1400]; try { var nextSeed = SeedEndpoint; int totalCount = 0; bool atEnd = false; while (!atEnd) { var curSeed = nextSeed; var endpoints = Util.RunWithRetries(() => SendAndReceive(udpSocket, recvData, region, filter, curSeed), this.Retries); if (endpoints == null) { callback(null, null, false); break; } nextSeed = endpoints.Last(); atEnd = nextSeed.Equals(SeedEndpoint); var serverList = endpoints.Select(ep => new Tuple <IPEndPoint, ServerInfo>(ep, null)).ToList(); if (atEnd) { serverList.RemoveAt(serverList.Count - 1); // remove the 0.0.0.0:0 end-of-list marker } ThreadPool.QueueUserWorkItem(y => callback(new ReadOnlyCollection <Tuple <IPEndPoint, ServerInfo> >(serverList), null, !atEnd)); totalCount += endpoints.Count; atEnd |= totalCount >= GetAddressesLimit; } //while (!nextSeed.Equals(SeedEndpoint) && totalCount < GetAddressesLimit); } catch (Exception ex) { callback(null, ex, false); } finally { try { udpSocket.Close(); } catch { } } }); }
/// <summary> /// Starts receiving socket addresses of servers. /// </summary> /// <param name="region">The region of the world that you wish to find servers in.</param> /// <param name="callback">Called when a batch of Socket addresses are received.</param> /// <param name="filter">Used to set filter on the type of server required.</param> public void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter = null) { if (IsListening) return; RegionCode = region; Callback = callback; Filter = filter; IsListening = true; IPEndPoint endPoint = SeedEndpoint; Msg = MasterUtil.BuildPacket(endPoint.ToString(), RegionCode, Filter); UdpSocket.Send(Msg); recvData = new byte[1400]; UdpSocket.BeginReceive(recvData, 0, recvData.Length, SocketFlags.None, recv, null); }
internal static byte[] BuildPacket(string endPoint, Region region, IpFilter filter) { List <byte> msg = new List <byte>(); msg.Add(Header); msg.Add((byte)region); msg.AddRange(Util.StringToBytes(endPoint)); msg.Add(0x00); if (filter != null) { msg.AddRange(Util.StringToBytes(ProcessFilter(filter))); } msg.Add(0x00); return(msg.ToArray()); }
internal static string ProcessFilter(IpFilter filter, bool inNorNand = false) { StringBuilder filterStr = new StringBuilder(); if (filter.App != 0) filterStr.Append(@"\appid\" + (int)filter.App); if (filter.IsDedicated) filterStr.Append(@"\type\d"); if (filter.IsSecure) filterStr.Append(@"\secure\1"); if (!string.IsNullOrEmpty(filter.GameDirectory)) filterStr.Append(@"\gamedir\" + filter.GameDirectory); if (!string.IsNullOrEmpty(filter.Map)) filterStr.Append(@"\map\" + filter.Map); if (filter.IsLinux) filterStr.Append(@"\linux\1"); if (filter.IsNotEmpty) filterStr.Append(@"\empty\1"); if (filter.IsNotFull) filterStr.Append(@"\full\1"); if (filter.IsProxy) filterStr.Append(@"\proxy\1"); if (filter.NApp != 0) filterStr.Append(@"\napp\" + filter.NApp); if (filter.IsNoPlayers) filterStr.Append(@"\noplayers\1"); if (filter.IsWhiteListed) filterStr.Append(@"\white\1"); if (!string.IsNullOrEmpty(filter.Sv_Tags)) filterStr.Append(@"\gametype\" + filter.Sv_Tags); if (!string.IsNullOrEmpty(filter.GameData)) filterStr.Append(@"\gamedata\" + filter.GameData); if (!string.IsNullOrEmpty(filter.GameDataOr)) filterStr.Append(@"\gamedataor\" + filter.GameDataOr); if (!string.IsNullOrEmpty(filter.HostnameMatch)) filterStr.Append(@"\name_match\" + filter.HostnameMatch); if (filter.CollapseAddrHash) filterStr.Append(@"\collapse_addr_hash\1"); if (!string.IsNullOrEmpty(filter.GameAddr)) filterStr.Append(@"\gameaddr\").Append(filter.GameAddr); if (filter.Nor != null) filterStr.Append(SubFilter(filter.Nor, "nor", inNorNand)); if (filter.Nand != null) filterStr.Append(SubFilter(filter.Nand, "nand", inNorNand)); filterStr.Append('\0'); return filterStr.ToString(); }
internal static string ProcessFilter(IpFilter filter) { StringBuilder filterStr = new StringBuilder(); if(filter.IsDedicated) filterStr.Append(@"\type\d"); if (filter.IsSecure) filterStr.Append(@"\secure\1"); if (!string.IsNullOrEmpty(filter.GameDirectory)) filterStr.Append(@"\gamedir\" + filter.GameDirectory); if (!string.IsNullOrEmpty(filter.Map)) filterStr.Append(@"\map\" + filter.Map); if (filter.IsLinux) filterStr.Append(@"\linux\1"); if (filter.IsNotEmpty) filterStr.Append(@"\empty\1"); if (filter.IsNotFull) filterStr.Append(@"\full\1"); if (filter.IsProxy) filterStr.Append(@"\proxy\1"); if (filter.App != 0) filterStr.Append(@"\appid\" + filter.App); if (filter.NApp != 0) filterStr.Append(@"\napp\" + filter.NApp); if (filter.IsNoPlayers) filterStr.Append(@"\noplayers\1"); if (filter.IsWhiteListed) filterStr.Append(@"\white\1"); if (!string.IsNullOrEmpty(filter.Sv_Tags)) filterStr.Append(@"\gametype\" + filter.Sv_Tags); if (!string.IsNullOrEmpty(filter.GameData)) filterStr.Append(@"\gamedata\" + filter.GameData); if (!string.IsNullOrEmpty(filter.GameDataOr)) filterStr.Append(@"\gamedataor\" + filter.GameDataOr); if (filter.IpAddr != null && filter.IpAddr.Length > 0) { foreach (var ipaddr in filter.IpAddr) { if (!string.IsNullOrEmpty(ipaddr)) { filterStr.Append(@"\gameaddr\").Append(ipaddr); } } } //filterStr.Append('\0'); return filterStr.ToString(); }
/// <summary> /// Starts receiving socket addresses of servers. /// </summary> /// <param name="region">The region of the world that you wish to find servers in.</param> /// <param name="callback">Called when a batch of Socket addresses are received.</param> /// <param name="filter">Used to set filter on the type of server required.</param> public void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter = null) { if (IsListening) { return; } RegionCode = region; Callback = callback; Filter = filter; IsListening = true; IPEndPoint endPoint = SeedEndpoint; Msg = MasterUtil.BuildPacket(endPoint.ToString(), RegionCode, Filter); UdpSocket.Send(Msg); recvData = new byte[1400]; UdpSocket.BeginReceive(recvData, 0, recvData.Length, SocketFlags.None, recv, null); }
public void GetAddresses(Region region, IpFilter filter, int maxResults, MasterIpCallback callback) { try { using (var client = new XWebClient()) { var text = client.DownloadString(this.url); if (text == null) { callback(null); return; } var lines = text.Split('\n'); var endpoints = new List<IPEndPoint>(lines.Length); int i = 0; foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line)) continue; var parts = line.Split(':'); if (parts.Length != 2) continue; IPAddress addr; int port; if (IPAddress.TryParse(parts[0], out addr) && int.TryParse(parts[1].TrimEnd(), out port)) { endpoints.Add(new IPEndPoint(addr, port)); if (++i == maxResults) break; } } endpoints.Add(new IPEndPoint(IPAddress.Any, 0)); callback(new ReadOnlyCollection<IPEndPoint>(endpoints)); } } catch { callback(null); } }
const string SteamWebApiKey = "B7D245299F6F990504A86FF91EC9D6BD"; // create an account and get a steam web api key at http://steamcommunity.com/dev/apikey /// <summary> /// Gets a server list from the Steam master server. /// The callback is invoked from a background thread every time a batch of servers is received. /// The end of the list is marked with an IPEndPoint of 0.0.0.0:0 /// In case of a timeout or an exception, the callback is invoked with a NULL parameter value. /// </summary> /// <exception cref="InvalidOperationException">Thrown if the object is still busy handling a previous call to GetAddresses</exception> public override void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter) { ThreadPool.QueueUserWorkItem(x => { try { using (var cli = new XWebClient()) { var filters = MasterUtil.ProcessFilter(filter); var url = $"https://api.steampowered.com/IGameServersService/GetServerList/v1/?key={SteamWebApiKey}&format=xml&filter={filters}&limit={GetAddressesLimit}"; var xml = cli.DownloadString(url); var ser = new XmlSerializer(typeof(Response)); var resp = (Response)ser.Deserialize(new StringReader(xml)); var endpoints = new List <Tuple <IPEndPoint, ServerInfo> >(); foreach (var msg in resp.Servers) { try { int i = msg.addr.IndexOf(':'); if (i > 0) { var info = ConvertToServerInfo(msg); endpoints.Add(new Tuple <IPEndPoint, ServerInfo>(info.EndPoint, info)); } } catch { } } callback(new ReadOnlyCollection <Tuple <IPEndPoint, ServerInfo> >(endpoints), null, false); } } catch (Exception ex) { callback(null, ex, false); } }); }
public abstract void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter);
private ReadOnlyCollection <IPEndPoint> SendAndReceive(Socket udpSocket, byte[] recvData, Region region, IpFilter filter, IPEndPoint seed) { var msg = MasterUtil.BuildPacket(seed.ToString(), region, filter); udpSocket.Send(msg); int len = udpSocket.Receive(recvData, 0, recvData.Length, SocketFlags.None); byte[] data = new byte[len]; Array.Copy(recvData, data, data.Length); return(MasterUtil.ProcessPacket(data)); }
public void GetAddresses(Region region, IpFilter filter, int maxResults, MasterIpCallback callback) { var master = new MasterServer(masterServerEndPoint); master.GetAddressesLimit = maxResults; master.GetAddresses(region, callback, filter); }
public void ReloadServerList(IPEndPoint masterServerEndPoint, int maxResults, Game steamAppId, Region region, bool queryServerRules) { this.currentRequest.IsCancelled = true; MasterServer master = new MasterServer(masterServerEndPoint); master.GetAddressesLimit = maxResults; IpFilter filter = new IpFilter(); filter.App = steamAppId; var request = new UpdateRequest(maxResults, queryServerRules); // use local var for thread safety this.currentRequest = request; master.GetAddresses(region, endpoints => OnMasterServerReceive(request, endpoints), filter); }
/// <summary> /// Gets a server list from the Steam master server. /// The callback is invoked from a background thread every time a batch of servers is received. /// The end of the list is marked with an IPEndPoint of 0.0.0.0:0 /// In case of a timeout or an exception, the callback is invoked with a NULL parameter value. /// </summary> /// <exception cref="InvalidOperationException">Thrown if the object is still busy handling a previous call to GetAddresses</exception> public void GetAddresses(Region region, MasterIpCallback callback, IpFilter filter) { ThreadPool.QueueUserWorkItem(x => { #if true try { using (var cli = new XWebClient()) { var filters = MasterUtil.ProcessFilter(filter); var url = $"https://api.steampowered.com/IGameServersService/GetServerList/v1/?key={SteamWebApiKey}&format=xml&filter={filters}&limit={GetAddressesLimit}"; var xml = cli.DownloadString(url); var ser = new XmlSerializer(typeof(Response)); var resp = (Response)ser.Deserialize(new StringReader(xml)); var endpoints = new List <Tuple <IPEndPoint, ServerInfo> >(); foreach (var msg in resp.Servers) { try { int i = msg.addr.IndexOf(':'); if (i > 0) { var info = ConvertToServerInfo(msg); endpoints.Add(new Tuple <IPEndPoint, ServerInfo>(info.EndPoint, info)); } } catch { } } callback(new ReadOnlyCollection <Tuple <IPEndPoint, ServerInfo> >(endpoints), null); } } catch (Exception ex) { callback(null, ex); } #else var udpSocket = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, ProtocolType.Udp); udpSocket.SendTimeout = 500; udpSocket.ReceiveTimeout = 500; udpSocket.Connect(endPoint); byte[] recvData = new byte[1400]; try { var nextSeed = SeedEndpoint; int totalCount = 0; do { var curSeed = nextSeed; var endpoints = Util.RunWithRetries(() => SendAndReceive(udpSocket, recvData, region, filter, curSeed), this.Retries); if (endpoints == null) { callback(null); break; } ThreadPool.QueueUserWorkItem(y => callback(endpoints, null)); totalCount += endpoints.Count; nextSeed = endpoints.Last(); } while (!nextSeed.Equals(SeedEndpoint) && totalCount < GetAddressesLimit); } catch (Exception ex) { callback(null, ex); } finally { try { udpSocket.Close(); } catch { } } #endif }); }
internal static string ProcessFilter(IpFilter filter) { StringBuilder filterStr = new StringBuilder(); if (filter.IsDedicated) { filterStr.Append(@"\type\d"); } if (filter.IsSecure) { filterStr.Append(@"\secure\1"); } if (!string.IsNullOrEmpty(filter.GameDirectory)) { filterStr.Append(@"\gamedir\" + filter.GameDirectory); } if (!string.IsNullOrEmpty(filter.Map)) { filterStr.Append(@"\map\" + filter.Map); } if (filter.IsLinux) { filterStr.Append(@"\linux\1"); } if (filter.IsNotEmpty) { filterStr.Append(@"\empty\1"); } if (filter.IsNotFull) { filterStr.Append(@"\full\1"); } if (filter.IsProxy) { filterStr.Append(@"\proxy\1"); } if (filter.App != 0) { filterStr.Append(@"\appid\" + filter.App); } if (filter.NApp != 0) { filterStr.Append(@"\napp\" + filter.NApp); } if (filter.IsNoPlayers) { filterStr.Append(@"\noplayers\1"); } if (filter.IsWhiteListed) { filterStr.Append(@"\white\1"); } if (!string.IsNullOrEmpty(filter.Sv_Tags)) { filterStr.Append(@"\gametype\" + filter.Sv_Tags); } if (!string.IsNullOrEmpty(filter.GameData)) { filterStr.Append(@"\gamedata\" + filter.GameData); } if (!string.IsNullOrEmpty(filter.GameDataOr)) { filterStr.Append(@"\gamedataor\" + filter.GameDataOr); } if (filter.IpAddr != null && filter.IpAddr.Length > 0) { foreach (var ipaddr in filter.IpAddr) { if (!string.IsNullOrEmpty(ipaddr)) { filterStr.Append(@"\gameaddr\").Append(ipaddr); } } } //filterStr.Append('\0'); return(filterStr.ToString()); }
internal static string ProcessFilter(IpFilter filter, bool inNorNand = false) { StringBuilder filterStr = new StringBuilder(); if (filter.App != 0) { filterStr.Append(@"\appid\" + (int)filter.App); } if (filter.IsDedicated) { filterStr.Append(@"\type\d"); } if (filter.IsSecure) { filterStr.Append(@"\secure\1"); } if (!string.IsNullOrEmpty(filter.GameDirectory)) { filterStr.Append(@"\gamedir\" + filter.GameDirectory); } if (!string.IsNullOrEmpty(filter.Map)) { filterStr.Append(@"\map\" + filter.Map); } if (filter.IsLinux) { filterStr.Append(@"\linux\1"); } if (filter.IsNotEmpty) { filterStr.Append(@"\empty\1"); } if (filter.IsNotFull) { filterStr.Append(@"\full\1"); } if (filter.IsProxy) { filterStr.Append(@"\proxy\1"); } if (filter.NApp != 0) { filterStr.Append(@"\napp\" + filter.NApp); } if (filter.IsNoPlayers) { filterStr.Append(@"\noplayers\1"); } if (filter.IsWhiteListed) { filterStr.Append(@"\white\1"); } if (!string.IsNullOrEmpty(filter.Sv_Tags)) { filterStr.Append(@"\gametype\" + filter.Sv_Tags); } if (!string.IsNullOrEmpty(filter.GameData)) { filterStr.Append(@"\gamedata\" + filter.GameData); } if (!string.IsNullOrEmpty(filter.GameDataOr)) { filterStr.Append(@"\gamedataor\" + filter.GameDataOr); } if (!string.IsNullOrEmpty(filter.HostnameMatch)) { filterStr.Append(@"\name_match\" + filter.HostnameMatch); } if (filter.CollapseAddrHash) { filterStr.Append(@"\collapse_addr_hash\1"); } if (!string.IsNullOrEmpty(filter.GameAddr)) { filterStr.Append(@"\gameaddr\").Append(filter.GameAddr); } if (!string.IsNullOrEmpty(filter.VersionMatch)) { filterStr.Append(@"\version_match\").Append(filter.VersionMatch); } if (filter.Nor != null) { filterStr.Append(SubFilter(filter.Nor, "nor", inNorNand)); } if (filter.Nand != null) { filterStr.Append(SubFilter(filter.Nand, "nand", inNorNand)); } filterStr.Append('\0'); return(filterStr.ToString()); }
protected void ReloadServerList() { if (this.ignoreUiEvents > 0) return; if (this.viewModel.Source != TabViewModel.SourceType.MasterServer) { this.RefreshServerInfo(); return; } this.UpdateViewModel(); if (this.viewModel.InitialGameID == 0) // this would result in a truncated list of all games return; this.SetStatusMessage("Requesting server list from master server..."); IpFilter filter = new IpFilter(); filter.App = (Game)this.viewModel.InitialGameID; filter.IsNotEmpty = !this.viewModel.GetEmptyServers; filter.IsNotFull = !this.viewModel.GetFullServers; filter.GameDirectory = this.viewModel.FilterMod; filter.Map = this.viewModel.FilterMap; filter.Sv_Tags = this.ParseTags(this.viewModel.TagsInclude); if (this.viewModel.TagsExclude != "") { filter.Nor = new IpFilter(); filter.Nor.Sv_Tags = this.ParseTags(this.viewModel.TagsExclude); } this.CustomizeFilter(filter); queryLogic.ReloadServerList(this.viewModel.serverSource, 500, this.viewModel.MasterServerQueryLimit, QueryMaster.Region.Rest_of_the_world, filter); }
protected virtual void CustomizeFilter(IpFilter filter) { this.viewModel.gameExtension.CustomizeServerFilter(filter); }
public void ReloadServerList(IServerSource serverSource, int timeout, int maxResults, Region region, IpFilter filter) { this.currentRequest.IsCancelled = true; var extension = this.gameExtensions.Get(filter.App); var request = new UpdateRequest(filter.App, maxResults, timeout, extension); // use local var for thread safety this.currentRequest = request; serverSource.GetAddresses(region, filter, maxResults, endpoints => OnMasterServerReceive(request, endpoints)); }
private ReadOnlyCollection<IPEndPoint> SendAndReceive(Socket udpSocket, byte[] recvData, Region region, IpFilter filter, IPEndPoint seed) { var msg = MasterUtil.BuildPacket(seed.ToString(), region, filter); udpSocket.Send(msg); int len = udpSocket.Receive(recvData, 0, recvData.Length, SocketFlags.None); byte[] data = new byte[len]; Array.Copy(recvData, data, data.Length); return MasterUtil.ProcessPacket(data); }
private static string SubFilter(IpFilter filter, string verb, bool inCascade) { var text = ProcessFilter(filter, true); int count = 0; foreach (var ch in text) count += ch == '\\' ? 1 : 0; string prefix = inCascade ? "" : "\\" + verb + "\\" + (count/2); return prefix + text.TrimEnd('\0'); }