/// <summary>
        /// Connect to the given IP address using the port specified as part of the network parameters. Once construction
        /// is complete a functioning network channel is set up and running.
        /// </summary>
        /// <param name="peerAddress">IP address to connect to. IPv6 is not currently supported by BitCoin. If port is not positive the default port from params is used.</param>
        /// <param name="params">Defines which network to connect to and details of the protocol.</param>
        /// <param name="bestHeight">How many blocks are in our best chain</param>
        /// <param name="connectTimeout">Timeout in milliseconds when initially connecting to peer</param>
        /// <exception cref="IOException">If there is a network related failure.</exception>
        /// <exception cref="ProtocolException">If the version negotiation failed.</exception>
        public NetworkConnection(PeerAddress peerAddress, NetworkParameters @params, uint bestHeight, int connectTimeout)
        {
            _params = @params;
            _remoteIp = peerAddress.Addr;

            var port = (peerAddress.Port > 0) ? peerAddress.Port : @params.Port;

            var address = new IPEndPoint(_remoteIp, port);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Connect(address);
            _socket.SendTimeout = _socket.ReceiveTimeout = connectTimeout;

            _out = new NetworkStream(_socket, FileAccess.Write);
            _in = new NetworkStream(_socket, FileAccess.Read);

            // the version message never uses check-summing. Update check-summing property after version is read.
            _serializer = new BitcoinSerializer(@params, false);

            // Announce ourselves. This has to come first to connect to clients beyond v0.30.20.2 which wait to hear
            // from us until they send their version message back.
            WriteMessage(new VersionMessage(@params, bestHeight));
            // When connecting, the remote peer sends us a version message with various bits of
            // useful data in it. We need to know the peer protocol version before we can talk to it.
            _versionMessage = (VersionMessage) ReadMessage();
            // Now it's our turn ...
            // Send an ACK message stating we accept the peers protocol version.
            WriteMessage(new VersionAck());
            // And get one back ...
            ReadMessage();
            // Switch to the new protocol version.
            var peerVersion = _versionMessage.ClientVersion;
            _log.InfoFormat("Connected to peer: version={0}, subVer='{1}', services=0x{2:X}, time={3}, blocks={4}",
                            peerVersion,
                            _versionMessage.SubVer,
                            _versionMessage.LocalServices,
                            UnixTime.FromUnixTime(_versionMessage.Time),
                            _versionMessage.BestHeight
                );
            // BitCoinSharp is a client mode implementation. That means there's not much point in us talking to other client
            // mode nodes because we can't download the data from them we need to find/verify transactions.
            if (!_versionMessage.HasBlockChain())
            {
                // Shut down the socket
                try
                {
                    Shutdown();
                }
                catch (IOException)
                {
                    // ignore exceptions while aborting
                }
                throw new ProtocolException("Peer does not have a copy of the block chain.");
            }
            // newer clients use check-summing
            _serializer.UseChecksumming(peerVersion >= 209);
            // Handshake is done!
        }
 public VersionMessage(NetworkParameters @params, uint newBestHeight)
     : base(@params)
 {
     ClientVersion = NetworkParameters.ProtocolVersion;
     LocalServices = 0;
     Time = UnixTime.ToUnixTime(DateTime.UtcNow);
     // Note that the official client doesn't do anything with these, and finding out your own external IP address
     // is kind of tricky anyway, so we just put nonsense here for now.
     MyAddr = new PeerAddress(IPAddress.Loopback, @params.Port, 0);
     TheirAddr = new PeerAddress(IPAddress.Loopback, @params.Port, 0);
     SubVer = "BitCoinSharp 0.1";
     BestHeight = newBestHeight;
 }
 /// <exception cref="BitCoinSharp.ProtocolException" />
 protected override void Parse()
 {
     ClientVersion = ReadUint32();
     LocalServices = ReadUint64();
     Time = ReadUint64();
     MyAddr = new PeerAddress(Params, Bytes, Cursor, 0);
     Cursor += MyAddr.MessageSize;
     TheirAddr = new PeerAddress(Params, Bytes, Cursor, 0);
     Cursor += TheirAddr.MessageSize;
     // uint64 localHostNonce  (random data)
     // We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where
     // there are NATs and proxies in the way. However we don't listen for inbound connections so it's irrelevant.
     _localHostNonce = ReadUint64();
     //   string subVer  (currently "")
     SubVer = ReadStr();
     //   int bestHeight (size of known block chain).
     BestHeight = ReadUint32();
 }
 /// <exception cref="ProtocolException"/>
 protected override void Parse()
 {
     var numAddresses = ReadVarInt();
     // Guard against ultra large messages that will crash us.
     if (numAddresses > _maxAddresses)
         throw new ProtocolException("Address message too large.");
     Addresses = new List<PeerAddress>((int) numAddresses);
     for (var i = 0UL; i < numAddresses; i++)
     {
         var addr = new PeerAddress(Params, Bytes, Cursor, ProtocolVersion);
         Addresses.Add(addr);
         Cursor += addr.MessageSize;
     }
 }
Exemple #5
0
 /// <summary>
 /// Add an address to the list of potential peers to connect to.
 /// </summary>
 public void AddAddress(PeerAddress peerAddress)
 {
     // TODO(miron) consider de-duplication
     _inactives.Add(peerAddress);
 }