public void StartListening(ServerInfoReceiveHandler sirh) { // Start listening. udpclient.BeginReceive(new AsyncCallback(ServerInfoReceiveHandler.Receive), sirh); }
public static void Receive(IAsyncResult ar) { ServerInfoReceiveHandler sirh = (ServerInfoReceiveHandler)ar.AsyncState; byte[] byPacket = sirh.udpclient.EndReceive(ar, ref sirh.ipepRemote); // Analyse the packet. BinaryReader br = new BinaryReader(new MemoryStream(byPacket)); // Get the checksum. uint uiChecksum = br.ReadUInt32(); // Skip ack and ackreturn and get packet type. br.ReadBytes(2); byte byPacketType = br.ReadByte(); // Only interested in valid PT_SERVERINFO packets. if (byPacketType == PT_SERVERINFO && uiChecksum == SRB2Checksum(byPacket)) { bool bMalformed = true; // Skip padding. br.ReadByte(); // Remember where we are. long iPacketStart = br.BaseStream.Position; // Try to interpret the packet in each recognised format. foreach (ServerInfoVer siv in Enum.GetValues(typeof(ServerInfoVer))) { SRB2ServerInfo srb2si; byte byNumWads = 0; srb2si.siv = siv; br.BaseStream.Position = iPacketStart; // Get address from socket. srb2si.strAddress = sirh.ipepRemote.Address.ToString(); srb2si.unPort = unchecked ((ushort)sirh.ipepRemote.Port); // Get version. byte byVersion = br.ReadByte(); if (siv == ServerInfoVer.SIV_PREME) { br.ReadBytes(3); uint uiSubVersion = br.ReadUInt32(); // Format version. // MattW_CFI: I hope you don't mind this exception, Oogaland, but 0.01.6 looks odd >_> if (byVersion == 1 && uiSubVersion == 6) { srb2si.strVersion = "X.01.6"; } else { srb2si.strVersion = byVersion.ToString(); } //srb2si.strVersion = String.Format("{0}.{1:00}.{2}", byVersion / 100, byVersion % 100, uiSubVersion); } else { byte bySubVersion = br.ReadByte(); // Format version. //srb2si.strVersion = String.Format("{0}.{1:00}.{2}", byVersion / 100, byVersion % 100, bySubVersion); srb2si.strVersion = byVersion.ToString(); } srb2si.byPlayers = br.ReadByte(); srb2si.byMaxplayers = br.ReadByte(); srb2si.byGametype = br.ReadByte(); srb2si.bModified = (br.ReadByte() != 0); if (siv == ServerInfoVer.SIV_ME) { byNumWads = br.ReadByte(); } srb2si.sbyAdminplayer = br.ReadSByte(); if (siv == ServerInfoVer.SIV_PREME) { br.ReadBytes(3); } // Calculate ping. srb2si.uiTime = unchecked ((uint)((long)(DateTime.Now.Ticks / 10000 - br.ReadUInt32()) % ((long)UInt32.MaxValue + 1))); if (siv == ServerInfoVer.SIV_PREME) { br.ReadUInt32(); } // Get and tidy map name. if (siv == ServerInfoVer.SIV_PREME) { srb2si.strMapName = ReadFixedLengthStr(br, 8); srb2si.strName = ReadFixedLengthStr(br, MAXSERVERNAME); } else { srb2si.strName = ReadFixedLengthStr(br, MAXSERVERNAME); srb2si.strMapName = ReadFixedLengthStr(br, 8); } if (siv == ServerInfoVer.SIV_PREME) { byNumWads = br.ReadByte(); } // Create new list of strings of initial size equal to number of wads. srb2si.listFiles = new List <AddedWad>(byNumWads); // Get the files info. byte[] byFiles = br.ReadBytes(siv == ServerInfoVer.SIV_PREME ? 4096 : 936); BinaryReader brFiles = new BinaryReader(new MemoryStream(byFiles)); // Extract the filenames. try { for (int i = 0; i < byNumWads; i++) { bool bFullString = false; AddedWad aw = new AddedWad(); if (siv == ServerInfoVer.SIV_PREME) { aw.bImportant = brFiles.ReadByte() != 0; aw.downloadtype = (DownloadTypes)brFiles.ReadByte(); } else { byte byFileStatus = brFiles.ReadByte(); aw.bImportant = (byFileStatus & 0xF) != 0; aw.downloadtype = (DownloadTypes)(byFileStatus >> 4); } aw.uiSize = brFiles.ReadUInt32(); // Work out how long the string is. int iStringPos = (int)brFiles.BaseStream.Position; while (iStringPos < byFiles.Length && byFiles[iStringPos] != 0) { iStringPos++; } // Make sure it's not longer than the max name length. if (iStringPos - (int)brFiles.BaseStream.Position > MAX_WADPATH) { bFullString = true; iStringPos = MAX_WADPATH + (int)brFiles.BaseStream.Position; } // Get the info and add it, if possible. if (iStringPos > (int)brFiles.BaseStream.Position) { aw.strFilename = Encoding.ASCII.GetString(brFiles.ReadBytes(iStringPos - (int)brFiles.BaseStream.Position)); srb2si.listFiles.Add(aw); } // Skip nul. if (!bFullString) { brFiles.ReadByte(); } // Skip the md5sum. brFiles.ReadBytes(16); } // Okay, done! Do something useful with the server info. sirh.ProcessServerInfo(srb2si); // If we got this far without an exception, leave the foreach loop. bMalformed = false; break; } catch (EndOfStreamException) { // Packet doesn't match supposed type, so we swallow the exception // and try remaining types. } catch (Exception e) { sirh.HandleException(e); break; } } if (bMalformed) { sirh.HandleException(new Exception("Received invalid PT_SERVERINFO packet from " + sirh.ipepRemote.Address + ":" + sirh.ipepRemote.Port + ".")); } } // Resume listening. sirh.ipepRemote = new IPEndPoint(IPAddress.Any, 0); sirh.udpclient.BeginReceive(new AsyncCallback(Receive), sirh); }