using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Net; using System.IO; namespace SRB2Updater { class MSClient { private Socket socket; /// /// Constructs an MS client object. /// public MSClient() { socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); } /// /// Gets list of servers reported by the MS. /// /// Hostname or IP address of MS. /// Port of MS. /// List of running servers. public List GetServerList(string strAddress, ushort unPort) { // Resolve the address if necessary. IPHostEntry iphe = Dns.GetHostEntry(strAddress); int iIPIndex = 0; while (iIPIndex < iphe.AddressList.Length && iphe.AddressList[iIPIndex].AddressFamily != socket.AddressFamily) { iIPIndex++; } // No addresses from our family? if (iIPIndex >= iphe.AddressList.Length) throw new SocketException((int)SocketError.HostNotFound); socket.Connect(iphe.AddressList[iIPIndex], unPort); // Send a request for the short server list. byte[] byPacket = new byte[12]; BinaryWriter bw = new BinaryWriter(new MemoryStream(byPacket)); bw.Write((uint)0); // Unused bw.Write((uint)IPAddress.HostToNetworkOrder(205)); // GET_SHORT_SERVER_MSG bw.Write((uint)0); // Length of tail. socket.Send(byPacket); List listServers = new List(); // Don't sit and wait for ever. socket.ReceiveTimeout = 10000; // Keep reading packets. We break if we receive the sentinel end-packet. byte[] byServer = new byte[12 + 80]; while (true) { int iLen = socket.Receive(byServer); BinaryReader br = new BinaryReader(new MemoryStream(byServer)); // Ignore the first eight bytes. br.ReadInt64(); // Is that the list finished? int iTailLen = IPAddress.NetworkToHostOrder(br.ReadInt32()); if (iTailLen == 0) break; else if (iTailLen != iLen - 12) { // MS is in a bad mood. //throw new Exception("Bad packet."); break; } // Otherwise, add the server to the list. MSServerEntry msse = new MSServerEntry(); br.ReadBytes(16); // Skip. msse.strAddress = Encoding.ASCII.GetString(br.ReadBytes(16)); string str = Encoding.ASCII.GetString(br.ReadBytes(8)); int iPos = str.IndexOf("\0"); if (iPos >= 0) str = str.Remove(iPos); msse.unPort = Convert.ToUInt16(str); msse.strName = Encoding.ASCII.GetString(br.ReadBytes(32)); iPos = msse.strName.IndexOf("\0"); if (iPos >= 0) msse.strName = msse.strName.Remove(iPos); msse.strVersion = Encoding.ASCII.GetString(br.ReadBytes(8)); iPos = msse.strVersion.IndexOf("\0"); if (iPos >= 0) msse.strVersion = msse.strVersion.Remove(iPos); listServers.Add(msse); } return listServers; } } public struct MSServerEntry { public string strAddress; public ushort unPort; public string strName; public string strVersion; public bool bPermanent; } }