private async Task <Message> WireDecodeMessage(UInt32 magic) { var command = DataDecoder.DecodeFixedString(await ReceiveExactly(12)); var payloadSize = DataDecoder.DecodeUInt32(await ReceiveExactly(4)); var payloadChecksum = DataDecoder.DecodeUInt32(await ReceiveExactly(4)); var payload = await ReceiveExactly(payloadSize.ToIntChecked()); if (!Messaging.VerifyPayloadChecksum(payloadChecksum, payload)) { throw new Exception($"Checksum failed for {command}"); } var message = new Message ( Magic: magic, Command: command, PayloadSize: payloadSize, PayloadChecksum: payloadChecksum, Payload: payload.ToImmutableArray() ); switch (message.Command) { case "addr": { var addressPayload = NetworkEncoder.DecodeAddressPayload(payload); OnReceivedAddresses?.Invoke(owner, addressPayload.NetworkAddresses); } break; case "alert": { var alertPayload = NetworkEncoder.DecodeAlertPayload(payload); } break; case "block": { var block = DataDecoder.DecodeBlock(null, payload); OnBlock?.Invoke(owner, block); } break; case "getblocks": { var getBlocksPayload = NetworkEncoder.DecodeGetBlocksPayload(payload); OnGetBlocks?.Invoke(owner, getBlocksPayload); } break; case "getheaders": { var getHeadersPayload = NetworkEncoder.DecodeGetBlocksPayload(payload); OnGetHeaders?.Invoke(owner, getHeadersPayload); } break; case "getdata": { var invPayload = NetworkEncoder.DecodeInventoryPayload(payload); OnGetData?.Invoke(owner, invPayload); } break; case "headers": { var blockHeaders = ImmutableList.CreateBuilder <BlockHeader>(); var offset = 0; var headerCount = payload.ReadVarInt(ref offset).ToIntChecked(); for (var i = 0; i < headerCount; i++) { var blockHeader = DataDecoder.DecodeBlockHeader(null, payload, ref offset); // ignore tx count var int payload.ReadVarInt(ref offset); blockHeaders.Add(blockHeader); } OnBlockHeaders?.Invoke(owner, blockHeaders.ToImmutable()); } break; case "inv": { var invPayload = NetworkEncoder.DecodeInventoryPayload(payload); OnInventoryVectors?.Invoke(owner, invPayload.InventoryVectors); } break; case "notfound": { var invPayload = NetworkEncoder.DecodeInventoryPayload(payload); OnNotFound?.Invoke(owner, invPayload.InventoryVectors); } break; case "ping": { OnPing?.Invoke(owner, payload.ToImmutableArray()); } break; case "tx": { var tx = DataDecoder.DecodeEncodedTx(null, payload); OnTransaction?.Invoke(owner, tx); } break; case "version": { var versionPayload = NetworkEncoder.DecodeVersionPayload(payload, payload.Length); OnVersion?.Invoke(owner, versionPayload); } break; case "verack": { OnVersionAcknowledged?.Invoke(owner); } break; default: { logger.Warn($"Unhandled incoming message: {message.Command}"); } break; } //TODO //if (payloadStream.Position != payloadStream.Length) //{ // var exMessage = $"Wrong number of bytes read for {message.Command}, parser error: read {payloadStream.Position} bytes from a {payloadStream.Length} byte payload"; // Debug.WriteLine(exMessage); // throw new Exception(exMessage); //} return(message); }
private async Task ReadStream() { while (!Closing) { try { //try to read a header var hdata = new byte[24]; await Stream.ReadAsyncExact(hdata, 0, hdata.Length); var h = new MessageHeader(); h.ReadFromPayload(hdata, 0); if (h != null) { //read the payload var pl = new byte[h.PayloadSize]; await Stream.ReadAsyncExact(pl, 0, pl.Length); bool checksumOk = false; //verify hash using (var sha = SHA256.Create()) { var h1 = sha.ComputeHash(pl); var h2 = sha.ComputeHash(h1); checksumOk = h2[0] == h.Checksum[0] && h2[1] == h.Checksum[1] && h2[2] == h.Checksum[2] && h2[3] == h.Checksum[3]; } if (checksumOk) { switch (h.Command) { case "addr\0\0\0\0\0\0\0\0": { if (OnAddr != null) { var a = new Addr(); a.ReadFromPayload(pl, 0); await OnAddr?.Invoke(this, a); } break; } case "alert\0\0\0\0\0\0\0": { if (OnAlert != null) { var a = new Alert(); a.ReadFromPayload(pl, 0); await OnAlert?.Invoke(this, a); } break; } case "feefilter\0\0\0": { if (OnFeeFilter != null) { var f = new FeeFilter(); f.ReadFromPayload(pl, 0); await OnFeeFilter?.Invoke(this, f); } break; } case "filteradd\0\0\0": { if (OnFilterAdd != null) { var f = new FilterAdd(); f.ReadFromPayload(pl, 0); await OnFilterAdd?.Invoke(this, f); } break; } case "filterclear\0": { if (OnFilterClear != null) { var f = new FilterClear(); f.ReadFromPayload(pl, 0); await OnFilterClear?.Invoke(this, f); } break; } case "filterload\0\0": { if (OnFilterLoad != null) { var f = new FilterLoad(); f.ReadFromPayload(pl, 0); await OnFilterLoad?.Invoke(this, f); } break; } case "getaddr\0\0\0\0\0": { if (OnGetAddr != null) { var ga = new GetAddr(); ga.ReadFromPayload(pl, 0); await OnGetAddr?.Invoke(this, ga); } break; } case "getblocks\0\0\0": { if (OnGetBlocks != null) { var gb = new GetBlocks(); gb.ReadFromPayload(pl, 0); await OnGetBlocks?.Invoke(this, gb); } break; } case "getdata\0\0\0\0\0": { if (OnGetData != null) { var gd = new GetData(); gd.ReadFromPayload(pl, 0); await OnGetData?.Invoke(this, gd); } break; } case "getheaders\0\0": { if (OnGetHeaders != null) { var gh = new GetHeaders(); gh.ReadFromPayload(pl, 0); await OnGetHeaders?.Invoke(this, gh); } break; } case "headers\0\0\0\0\0": { if (OnHeaders != null) { var hd = new Headers(); hd.ReadFromPayload(pl, 0); await OnHeaders?.Invoke(this, hd); } break; } case "inv\0\0\0\0\0\0\0\0\0": { if (OnInv != null) { var iv = new Inv(); iv.ReadFromPayload(pl, 0); await OnInv?.Invoke(this, iv); } break; } case "mempool\0\0\0\0\0": { if (OnMemPool != null) { var mp = new MemPool(); mp.ReadFromPayload(pl, 0); await OnMemPool?.Invoke(this, mp); } break; } case "notfound\0\0\0\0": { if (OnNotFound != null) { var nf = new NotFound(); nf.ReadFromPayload(pl, 0); await OnNotFound?.Invoke(this, nf); } break; } case "ping\0\0\0\0\0\0\0\0": { if (OnPing != null) { var ping = new Ping(); ping.ReadFromPayload(pl, 0); await OnPing?.Invoke(this, ping); } break; } case "pong\0\0\0\0\0\0\0\0": { if (OnPong != null) { var pong = new Pong(); pong.ReadFromPayload(pl, 0); await OnPong?.Invoke(this, pong); } break; } case "reject\0\0\0\0\0\0": { if (OnReject != null) { var re = new Reject(); re.ReadFromPayload(pl, 0); await OnReject?.Invoke(this, re); } break; } case "sendheaders\0": { if (OnSendHeaders != null) { var sh = new SendHeaders(); sh.ReadFromPayload(pl, 0); await OnSendHeaders?.Invoke(this, sh); } break; } case "verack\0\0\0\0\0\0": { if (OnVerAck != null) { var va = new VerAck(); va.ReadFromPayload(pl, 0); await OnVerAck.Invoke(this, va); } break; } case "version\0\0\0\0\0": { if (OnVersion != null) { var v = new bitcoin_lib.P2P.Version(""); v.ReadFromPayload(pl, 0); await OnVersion?.Invoke(this, v); } break; } default: { //Console.WriteLine($"Got cmd: {h.Command}"); break; } } } else { Closing = true; } } } catch (Exception ex) { Closing = true; } } }
public async Task <TestSession> ParseAsync(Stream stream, bool copyStreamContentToResult = false, CancellationToken token = new CancellationToken()) { var streamContentCopy = new MemoryStream(); var streamWriter = new StreamWriter(streamContentCopy, Encoding.UTF8); var streamReader = new StreamReader(stream, Encoding.UTF8); string yamlContent = String.Empty; bool parsingYaml = false; var testPlan = new TestPlan(); var results = new List <TestLine>(); uint tapVersion = 0; var sessionDiagnosticMessages = new List <string>(); string bailoutMessage = String.Empty; bool bailedOut = false; token.ThrowIfCancellationRequested(); var taskString = streamReader.ReadLineAsync(); await taskString; var line = taskString.Result; while (line != null) { token.ThrowIfCancellationRequested(); if (copyStreamContentToResult) { streamWriter.WriteLine(line); } var parseResult = ParseLine(line, parsingYaml); switch (parseResult) { case ParseResult.TestResult: var result = ParseTestResult(line, (uint)results.Count + 1); results.Add(result); try { OnTestResult?.Invoke(result); } catch (Exception e) { SendError(e); } break; case ParseResult.Error: if (!string.IsNullOrEmpty(line)) { var e = new TAPParserException($"TAP syntax error. Unrecognized line \"{line}\"."); SendError(e); } break; case ParseResult.Version: var v = ParseTAPVersion(line); try { OnVersion?.Invoke(v); } catch (Exception e) { SendError(e); } tapVersion = v; break; case ParseResult.YamlStart: parsingYaml = true; yamlContent = ""; break; case ParseResult.YamlEnd: parsingYaml = false; using (TextReader tr = new StringReader(yamlContent)) { dynamic yaml = m_deserializer.Deserialize(tr); var testLine = results.Last(); testLine.YAML = yaml; try { OnYaml?.Invoke(testLine, yaml); } catch (Exception e) { SendError(e); } } break; case ParseResult.YamlContent: yamlContent += line + "\n"; break; case ParseResult.TestPlan: var tp = ParseTestPlan(line); try { OnTestPlan?.Invoke(tp); } catch (Exception e) { SendError(e); } testPlan = tp; break; case ParseResult.Diagnostic: string diagnostic = s_diagnostics.Match(line).Groups["diagnostic"].Value.Trim(); if (results.Any()) { var testLine = results.Last(); testLine.DiagnosticMessages.Add(diagnostic); try { OnTestResultDiagnostic?.Invoke(testLine, diagnostic); } catch (Exception e) { SendError(e); } } else { sessionDiagnosticMessages.Add(diagnostic); try { OnDiagnostic?.Invoke(diagnostic); } catch (Exception e) { SendError(e); } } break; case ParseResult.BailOut: var message = s_bailout.Match(line).Groups["message"].Value.Trim(); bailedOut = true; try { OnBailout?.Invoke(message); } catch (Exception e) { SendError(e); } bailoutMessage = message; break; default: throw new ArgumentOutOfRangeException(); } taskString = streamReader.ReadLineAsync(); await taskString; line = taskString.Result; } int testCount = (int)testPlan.LastTestIndex - (int)testPlan.FirstTestIndex + 1; if (results.Count < testCount) { for (int i = results.Count + 1; i <= testCount; i++) { token.ThrowIfCancellationRequested(); var testLine = new TestLine { Description = "", Directive = "", Index = (uint)i, Status = TestResult.NotOk, }; results.Add(testLine); try { OnTestResult?.Invoke(testLine); } catch (Exception e) { SendError(e); } } } streamWriter.Flush(); streamContentCopy.Position = 0; return(new TestSession { TAPVersion = tapVersion, TestPlan = testPlan, Tests = results, DiagnosticMessages = sessionDiagnosticMessages, BailOutMessage = bailoutMessage, BailedOut = bailedOut, TAPContent = streamContentCopy }); }
public void ParseReply(string[] tokens) { ReplyCode code = (ReplyCode)int.Parse(tokens[1], CultureInfo.InvariantCulture); tokens[3] = RemoveLeadingColon(tokens[3]); switch (code) { //Messages sent upon successful registration case ReplyCode.RPL_WELCOME: case ReplyCode.RPL_YOURESERVICE: OnRegistered.Fire(this, new EventArgs()); break; case ReplyCode.RPL_MOTDSTART: case ReplyCode.RPL_MOTD: OnMotd?.Invoke(CondenseStrings(tokens, 3), false); break; case ReplyCode.RPL_ENDOFMOTD: OnMotd?.Invoke(CondenseStrings(tokens, 3), true); break; case ReplyCode.RPL_ISON: OnIson?.Invoke(tokens[3]); break; case ReplyCode.RPL_NAMREPLY: ProcessNamesReply(tokens, false); break; case ReplyCode.RPL_ENDOFNAMES: ProcessNamesReply(tokens, true); break; case ReplyCode.RPL_LIST: tokens[5] = RemoveLeadingColon(tokens[5]); OnList?.Invoke( tokens[3], int.Parse(tokens[4], CultureInfo.InvariantCulture), CondenseStrings(tokens, 5), false); break; case ReplyCode.RPL_LISTEND: OnList?.Invoke("", 0, "", true); break; case ReplyCode.ERR_NICKNAMEINUSE: case ReplyCode.ERR_NICKCOLLISION: tokens[4] = RemoveLeadingColon(tokens[4]); OnNickError.Fire(this, new NickErrorEventArgs(tokens[3], CondenseStrings(tokens, 4))); //Trace.WriteLine("Nick collision", "IRC"); break; case ReplyCode.RPL_NOTOPIC: OnError.Fire(this, new ErrorMessageEventArgs(code, CondenseStrings(tokens, 3))); break; case ReplyCode.RPL_TOPIC: tokens[4] = RemoveLeadingColon(tokens[4]); OnRecieveTopic?.Invoke(tokens[3], CondenseStrings(tokens, 4)); break; case ReplyCode.RPL_INVITING: OnInviteSent.Fire(this, new InviteEventArgs(tokens[3], tokens[4])); break; case ReplyCode.RPL_AWAY: OnAway.Fire(this, new AwayEventArgs(tokens[3], RemoveLeadingColon(CondenseStrings(tokens, 4)))); break; case ReplyCode.RPL_WHOREPLY: User user = new User(tokens[7], tokens[4], tokens[5]); OnWho?.Invoke( user, tokens[3], tokens[6], tokens[8], int.Parse(RemoveLeadingColon(tokens[9]), CultureInfo.InvariantCulture), tokens[10], false); break; case ReplyCode.RPL_ENDOFWHO: OnWho?.Invoke(User.Empty, "", "", "", 0, "", true); break; case ReplyCode.RPL_WHOISUSER: User whoUser = new User(tokens[3], tokens[4], tokens[5]); WhoisInfo whoisInfo = LookupInfo(whoUser.Nick); whoisInfo.user = whoUser; tokens[7] = RemoveLeadingColon(tokens[7]); whoisInfo.realName = CondenseStrings(tokens, 7); break; case ReplyCode.RPL_WHOISCHANNELS: WhoisInfo whoisChannelInfo = LookupInfo(tokens[3]); tokens[4] = RemoveLeadingColon(tokens[4]); int numberOfChannels = tokens.Length - 4; string[] channels = new String[numberOfChannels]; Array.Copy(tokens, 4, channels, 0, numberOfChannels); whoisChannelInfo.SetChannels(channels); break; case ReplyCode.RPL_WHOISSERVER: WhoisInfo whoisServerInfo = LookupInfo(tokens[3]); whoisServerInfo.ircServer = tokens[4]; tokens[5] = RemoveLeadingColon(tokens[5]); whoisServerInfo.serverDescription = CondenseStrings(tokens, 5); break; case ReplyCode.RPL_WHOISOPERATOR: WhoisInfo whoisOpInfo = LookupInfo(tokens[3]); whoisOpInfo.isOperator = true; break; case ReplyCode.RPL_WHOISIDLE: WhoisInfo whoisIdleInfo = LookupInfo(tokens[3]); whoisIdleInfo.idleTime = long.Parse(tokens[5], CultureInfo.InvariantCulture); break; case ReplyCode.RPL_ENDOFWHOIS: string nick = tokens[3]; WhoisInfo whoisEndInfo = LookupInfo(nick); OnWhois?.Invoke(whoisEndInfo); whoisInfos.Remove(nick); break; case ReplyCode.RPL_WHOWASUSER: User whoWasUser = new User(tokens[3], tokens[4], tokens[5]); tokens[7] = RemoveLeadingColon(tokens[7]); OnWhowas?.Invoke(whoWasUser, CondenseStrings(tokens, 7), false); break; case ReplyCode.RPL_ENDOFWHOWAS: OnWhowas?.Invoke(User.Empty, "", true); break; case ReplyCode.RPL_UMODEIS: { //First drop the '+' string chars = tokens[3].Substring(1); UserMode[] modes = Rfc2812Util.UserModesToArray(chars); OnUserModeRequest?.Invoke(modes); } break; case ReplyCode.RPL_CHANNELMODEIS: try { ChannelModeInfo[] modes = ChannelModeInfo.ParseModes(tokens, 4); OnChannelModeRequest?.Invoke(tokens[3], modes); } catch (Exception) { OnError.Fire(this, new ErrorMessageEventArgs(ReplyCode.UnparseableMessage, CondenseStrings(tokens, 0))); Debug.WriteLineIf(Rfc2812Util.IrcTrace.TraceWarning, "[" + Thread.CurrentThread.Name + "] Listener::ParseReply() Bad IRC MODE string=" + tokens[0]); } break; case ReplyCode.RPL_BANLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Ban, tokens[4], Rfc2812Util.UserFromString(tokens[5]), Convert.ToInt64(tokens[6], CultureInfo.InvariantCulture), false); break; case ReplyCode.RPL_ENDOFBANLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Ban, "", User.Empty, 0, true); break; case ReplyCode.RPL_INVITELIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Invitation, tokens[4], Rfc2812Util.UserFromString(tokens[5]), Convert.ToInt64(tokens[6]), false); break; case ReplyCode.RPL_ENDOFINVITELIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Invitation, "", User.Empty, 0, true); break; case ReplyCode.RPL_EXCEPTLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Exception, tokens[4], Rfc2812Util.UserFromString(tokens[5]), Convert.ToInt64(tokens[6]), false); break; case ReplyCode.RPL_ENDOFEXCEPTLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Exception, "", User.Empty, 0, true); break; case ReplyCode.RPL_UNIQOPIS: OnChannelList?.Invoke(tokens[3], ChannelMode.ChannelCreator, tokens[4], User.Empty, 0, true); break; case ReplyCode.RPL_VERSION: OnVersion?.Invoke(CondenseStrings(tokens, 3)); break; case ReplyCode.RPL_TIME: OnTime?.Invoke(CondenseStrings(tokens, 3)); break; case ReplyCode.RPL_INFO: OnInfo?.Invoke(CondenseStrings(tokens, 3), false); break; case ReplyCode.RPL_ENDOFINFO: OnInfo?.Invoke(CondenseStrings(tokens, 3), true); break; case ReplyCode.RPL_ADMINME: case ReplyCode.RPL_ADMINLOC1: case ReplyCode.RPL_ADMINLOC2: case ReplyCode.RPL_ADMINEMAIL: OnAdmin?.Invoke(RemoveLeadingColon(CondenseStrings(tokens, 3))); break; case ReplyCode.RPL_LUSERCLIENT: case ReplyCode.RPL_LUSEROP: case ReplyCode.RPL_LUSERUNKNOWN: case ReplyCode.RPL_LUSERCHANNELS: case ReplyCode.RPL_LUSERME: OnLusers?.Invoke(RemoveLeadingColon(CondenseStrings(tokens, 3))); break; case ReplyCode.RPL_LINKS: OnLinks?.Invoke(tokens[3], //mask tokens[4], //hostname int.Parse(RemoveLeadingColon(tokens[5]), CultureInfo.InvariantCulture), //hopcount CondenseStrings(tokens, 6), false); break; case ReplyCode.RPL_ENDOFLINKS: OnLinks?.Invoke(String.Empty, String.Empty, -1, String.Empty, true); break; case ReplyCode.RPL_STATSLINKINFO: case ReplyCode.RPL_STATSCOMMANDS: case ReplyCode.RPL_STATSUPTIME: case ReplyCode.RPL_STATSOLINE: OnStats?.Invoke(GetQueryType(code), RemoveLeadingColon(CondenseStrings(tokens, 3)), false); break; case ReplyCode.RPL_ENDOFSTATS: OnStats?.Invoke(Rfc2812Util.CharToStatsQuery(tokens[3][0]), RemoveLeadingColon(CondenseStrings(tokens, 4)), true); break; default: HandleDefaultReply(code, tokens); break; } }