/// <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! }
/// <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="remoteIp">IP address to connect to. IPv6 is not currently supported by BitCoin.</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="System.IO.IOException">If there is a network related failure.</exception> /// <exception cref="BitCoinSharp.ProtocolException">If the version negotiation failed.</exception> public NetworkConnection(IPAddress remoteIp, NetworkParameters @params, uint bestHeight, int connectTimeout) { _params = @params; _remoteIp = remoteIp; var address = new IPEndPoint(remoteIp, @params.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()) 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! }