private void recv(IAsyncResult res) { int bytesRev = 0; try { bytesRev = UdpSocket.EndReceive(res); } catch (ObjectDisposedException) { return; } var endpoints = MasterUtil.ProcessPacket(recvData.Take(bytesRev).ToArray()); //ThreadPool.QueueUserWorkItem(x => Callback(endpoints)); Callback(endpoints); if (!endpoints.Last().Equals(SeedEndpoint)) { Msg = MasterUtil.BuildPacket(endpoints.Last().ToString(), RegionCode, Filter); UdpSocket.Send(Msg); UdpSocket.BeginReceive(recvData, 0, recvData.Length, SocketFlags.None, recv, null); } else { IsListening = false; } }
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); } }); }
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)); }
/// <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); }
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); } }); }
/// <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 }); }