public static IBitcoinMessage Parse(BitcoinMessage message) { Func<BitcoinStreamReader, IBitcoinMessage> readMethod; if (!messageReadMethods.TryGetValue(message.Command, out readMethod)) { return null; } MemoryStream mem = new MemoryStream(message.Payload); using (BitcoinStreamReader reader = new BitcoinStreamReader(mem)) { return readMethod(reader); } }
private string FormatForLog(BitcoinMessage message) { StringBuilder sb = new StringBuilder(); BitcoinMessageFormatter formatter = new BitcoinMessageFormatter("\t"); sb.AppendFormat("{0} [{1} byte(s)]", message.Command, message.Payload.Length); try { IBitcoinMessage parsedMessage = BitcoinMessageParser.Parse(message); if (parsedMessage != null) { sb.Append("\n"); sb.Append(formatter.Format(parsedMessage)); } } catch (Exception e) { sb.AppendFormat("\n\tUnable to parse message: {0}", e.Message); } return sb.ToString(); }
/// <summary> /// Sends the message to the connected peer. /// <para/> /// Method is thread-safe. /// </summary> /// <param name="message">The message to send.</param> public void WriteMessage(BitcoinMessage message) { lock (writeLock) { byte[] commandBytes = Encoding.ASCII.GetBytes(message.Command); if (commandBytes.Length > MaxCommandLength) { //todo: handle correctly throw new BitcoinNetworkException($"Command length ({commandBytes.Length}) exeeds maximum command length ({MaxCommandLength})."); } byte[] header = new byte[MessageHeaderLength]; Array.Copy(magicBytes, 0, header, 0, 4); Array.Copy(commandBytes, 0, header, 4, commandBytes.Length); byte[] payloadLengthBytes = BitConverter.GetBytes(message.Payload.Length); Array.Copy(payloadLengthBytes, 0, header, 16, 4); byte[] checksum = sha256WriterAlg.ComputeHash(sha256WriterAlg.ComputeHash(message.Payload)); Array.Copy(checksum, 0, header, 20, 4); stream.Write(header, 0, header.Length); stream.Write(message.Payload, 0, message.Payload.Length); } if (logger.IsTraceEnabled) { logger.Trace("Sent message: {0}", FormatForLog(message)); } }
public BitcoinMessage ReadMessage() { byte[] header = ReadBytes(MessageHeaderLength); int payloadLength = BitConverter.ToInt32(header, 16); for (int i = 0; i < 4; i++) { if (header[i] != magicBytes[i]) { //todo: handle correctly throw new Exception("The magic value is invalid."); } } if (payloadLength < 0) { //todo: handle correctly throw new Exception(string.Format("Invalid payload length: ({0}).", payloadLength)); } //todo: move to const if (payloadLength > MaxPayloadLength) { //todo: handle correctly throw new Exception(string.Format("Payload length is too large: {0}.", payloadLength)); } int commandLength = 12; while (commandLength > 0 && header[commandLength + 4 - 1] == 0) { commandLength--; } string command = Encoding.ASCII.GetString(header, 4, commandLength); byte[] payload = ReadBytes(payloadLength); byte[] checksum = sha256ReaderAlg.ComputeHash(sha256ReaderAlg.ComputeHash(payload)); for (int i = 0; i < 4; i++) { if (header[20 + i] != checksum[i]) { //todo: handle correctly throw new Exception("The checksum is invalid."); } } BitcoinMessage message = new BitcoinMessage(command, payload); if (logger.IsTraceEnabled) { logger.Trace("Received message: {0}", FormatForLog(message)); } return message; }
private void HandleMessage(BitcoinMessage message) { if (message.Command == RejectMessage.Command) { //todo: stop endpoint / allow messageHandler to process it (be careful of reject message loop)? return; } IBitcoinMessage parsedMessage = BitcoinMessageParser.Parse(message); if (parsedMessage is PingMessage) { PingMessage ping = (PingMessage) parsedMessage; WriteMessage(new PongMessage(ping.Nonce)); } if (parsedMessage == null) { //todo: this is a misuse of the interface parsedMessage = message; } if (messageHandler == null || !messageHandler(this, parsedMessage)) { WriteMessage(new RejectMessage(message.Command, RejectMessage.RejectReason.Malformed, "Unknown command.")); } }
public void WriteMessage(IBitcoinMessage message) { BitcoinMessage rawMessage = new BitcoinMessage(message.Command, BitcoinStreamWriter.GetBytes(message.Write)); conn.WriteMessage(rawMessage); }