public void Listen(int maxIncoming = 8) { if (this.socket != null) { throw new InvalidOperationException("Already listening"); } using (this.trace.Open()) { try { this.socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); this.socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); this.socket.Bind(this.LocalEndpoint); this.socket.Listen(maxIncoming); NodeServerTrace.Information("Listening..."); this.BeginAccept(); } catch (Exception ex) { NodeServerTrace.Error("Error while opening the Protocol server", ex); throw; } } }
public void Dispose() { if (!this.cancel.IsCancellationRequested) { this.cancel.Cancel(); this.trace.LogInside(() => NodeServerTrace.Information("Stopping network peer server...")); lock (this.resources) { foreach (IDisposable resource in this.resources) { resource.Dispose(); } } try { this.ConnectedNetworkPeers.DisconnectAll(); } finally { if (this.socket != null) { Utils.SafeCloseSocket(this.socket); this.socket = null; } } } }
internal void ExternalAddressDetected(IPAddress ipAddress) { if (!this.ExternalEndpoint.Address.IsRoutable(this.AllowLocalPeers) && ipAddress.IsRoutable(this.AllowLocalPeers)) { NodeServerTrace.Information("New externalAddress detected " + ipAddress); this.ExternalEndpoint = new IPEndPoint(ipAddress, this.ExternalEndpoint.Port); } }
public async Task <bool> EnsureMapping() { NodeServerTrace.Information("EnsureMapping"); var device = await GetNatDeviceAsync(); return(device == null ? false : await device.GetSpecificMappingAsync(Protocol.Tcp, _ServerPort).ContinueWith(t => { if (t.IsFaulted) { NodeServerTrace.Error("GetExternalIP", t.Exception); return false; } var mapping = t.Result; try { if (mapping != null && !mapping.PrivateIP.Equals(InternalIPAddress)) { NodeServerTrace.Information($"existing mapping mismatch. got: {mapping.PrivateIP}, need: {InternalIPAddress}"); _NatDevice.DeletePortMapAsync(mapping).Wait(); mapping = null; } if (mapping == null) { NodeServerTrace.Information($"creaing mapping with IP: {InternalIPAddress}"); _NatDevice.CreatePortMapAsync( new Mapping( Protocol.Tcp, InternalIPAddress, _ServerPort, _ServerPort, 0, //TODO: session lifetime? MAPPING_DESC ) ).Wait(); } IEnumerable <Mapping> exisingMappings = _NatDevice.GetAllMappingsAsync().Result; return exisingMappings.Count(exisintMapping => exisintMapping.PublicPort == _ServerPort) == 1; } catch (Exception e) { NodeServerTrace.Error("Mapping", e); return false; } })); }
public bool Start() { try { _Server.Listen(); NodeServerTrace.Information("Server listening"); return(true); } catch (Exception e) { NodeServerTrace.Error("Listen", e); } return(false); }
private void BeginAccept() { if (this.cancel.IsCancellationRequested) { NodeServerTrace.Information("Stop accepting connection..."); return; } NodeServerTrace.Information("Accepting connection..."); var args = new SocketAsyncEventArgs(); args.Completed += Accept_Completed; if (!this.socket.AcceptAsync(args)) { this.EndAccept(args); } }
public Server(IPAddress externalAddress, NetworkInfo network, NodeConnectionParameters nodeConnectionParameters) { _Server = new NodeServer(network, internalPort: network.DefaultPort); OwnResource(_Server); if (externalAddress != null) { var externalEndpoint = new IPEndPoint(externalAddress, network.DefaultPort); AddressManager addressManager = AddressManagerBehavior.GetAddrman(nodeConnectionParameters); addressManager.Add(new NetworkAddress(externalEndpoint)); addressManager.Connected(new NetworkAddress(externalEndpoint)); _Server.ExternalEndpoint = externalEndpoint; } _Server.InboundNodeConnectionParameters = nodeConnectionParameters; _Server.AllowLocalPeers = false; //TODO NodeServerTrace.Information($"Server setup at {externalAddress}"); }
public NATManager(int serverPort) //TODO: check internet connection is active { IPAddress[] PrivateIPs = NBitcoin.Utils.GetAllLocalIPv4(); _ServerPort = serverPort; if (PrivateIPs.Count() == 0) { NodeServerTrace.Information("Warning, local addresses not found"); InternalIPAddress = null; } else { InternalIPAddress = PrivateIPs.First(); if (PrivateIPs.Count() > 1) { NodeServerTrace.Information("Warning, found " + PrivateIPs.Count() + " internal addresses"); } } }
private void FireCallbacks(List <Operation> operations) { foreach (var operation in operations) { var newOperation = this.NewOperation; if (newOperation != null) { foreach (var handler in newOperation.GetInvocationList().Cast <NewTrackerOperation>()) { try { handler.DynamicInvoke(this, operation); } catch (TargetInvocationException ex) { NodeServerTrace.Error("Error while calling Tracker callback", ex.InnerException); } } } } }
public async Task <NatDevice> GetNatDeviceAsync() { var nat = new NatDiscoverer(); var cts = new CancellationTokenSource(TIMEOUT); if (_NatDevice != null) { return(_NatDevice); } await _SemaphoreSlim.WaitAsync(); NodeServerTrace.Information("NAT Device discovery started"); return(await nat.DiscoverDeviceAsync(PortMapper.Upnp, cts).ContinueWith(t => { _SemaphoreSlim.Release(); DeviceFound = t.Status != TaskStatus.Faulted; if (!DeviceFound) { NodeServerTrace.Information("NAT Device not found"); HasError = !(t.Exception.InnerException is NatDeviceNotFoundException); if (HasError) { NodeServerTrace.Error("NAT Device discovery", t.Exception); } return null; } else { _NatDevice = t.Result; } return _NatDevice; })); }
public async Task <bool> VerifyExternalIP() { NodeServerTrace.Information("VerifyExternalIP"); var device = await GetNatDeviceAsync(); return(device == null ? false : await device.GetExternalIPAsync().ContinueWith(t => { if (t.IsFaulted) { NodeServerTrace.Error("GetExternalIP", t.Exception); return false; } ExternalIPAddress = t.Result; if (ExternalIPAddress == null) { return false; } //try //{ // IPAddress ipAddress = ExternalTestingServicesHelper.GetExternalIPAsync().Result; // bool match = ipAddress.Equals(ExternalIPAddress); // Trace.Information("External IP " + (match ? "match" : "do not match")); // return match; //} //catch (Exception e) //{ // Trace.Error("GetExternalIP", e); // return false; //} return ExternalIPAddress.IsRoutable(false); })); }
private void ProcessMessageCore(IncomingMessage message) { if (message.Message.Payload is VersionPayload) { VersionPayload version = message.AssertPayload <VersionPayload>(); bool connectedToSelf = version.Nonce == this.Nonce; if ((message.NetworkPeer != null) && connectedToSelf) { NodeServerTrace.ConnectionToSelfDetected(); message.NetworkPeer.DisconnectAsync(); return; } if (message.NetworkPeer == null) { IPEndPoint remoteEndpoint = version.AddressFrom; if (!remoteEndpoint.Address.IsRoutable(this.AllowLocalPeers)) { // Send his own endpoint. remoteEndpoint = new IPEndPoint(((IPEndPoint)message.Socket.RemoteEndPoint).Address, this.Network.DefaultPort); } var peerAddress = new NetworkAddress() { Endpoint = remoteEndpoint, Time = DateTimeOffset.UtcNow }; NetworkPeer networkPeer = this.networkPeerFactory.CreateNetworkPeer(peerAddress, this.Network, CreateNetworkPeerConnectionParameters(), message.Socket, version); if (connectedToSelf) { networkPeer.SendMessage(CreateNetworkPeerConnectionParameters().CreateVersion(networkPeer.PeerAddress.Endpoint, this.Network)); NodeServerTrace.ConnectionToSelfDetected(); networkPeer.Disconnect(); return; } CancellationTokenSource cancel = new CancellationTokenSource(); cancel.CancelAfter(TimeSpan.FromSeconds(10.0)); try { this.ConnectedNetworkPeers.Add(networkPeer); networkPeer.StateChanged += Peer_StateChanged; networkPeer.RespondToHandShake(cancel.Token); } catch (OperationCanceledException ex) { NodeServerTrace.Error("The remote peer did not respond fast enough (10 seconds) to the handshake completion, dropping connection", ex); networkPeer.DisconnectAsync(); throw; } catch (Exception) { networkPeer.DisconnectAsync(); throw; } } } this.MessageReceived?.Invoke(this, message); }
private void EndAccept(SocketAsyncEventArgs args) { using (this.trace.Open()) { Socket client = null; try { if (args.SocketError != SocketError.Success) { throw new SocketException((int)args.SocketError); } client = args.AcceptSocket; if (this.cancel.IsCancellationRequested) { return; } NodeServerTrace.Information("Client connection accepted : " + client.RemoteEndPoint); var cancel = CancellationTokenSource.CreateLinkedTokenSource(this.cancel.Token); cancel.CancelAfter(TimeSpan.FromSeconds(10)); var stream = new NetworkStream(client, false); while (true) { if (this.ConnectedNetworkPeers.Count >= this.MaxConnections) { NodeServerTrace.Information("MaxConnections limit reached"); Utils.SafeCloseSocket(client); break; } cancel.Token.ThrowIfCancellationRequested(); PerformanceCounter counter; Message message = Message.ReadNext(stream, this.Network, this.Version, cancel.Token, out counter); this.messageProducer.PushMessage(new IncomingMessage() { Socket = client, Message = message, Length = counter.ReadBytes, NetworkPeer = null, }); if (message.Payload is VersionPayload) { break; } NodeServerTrace.Error("The first message of the remote peer did not contained a Version payload", null); } } catch (OperationCanceledException) { Utils.SafeCloseSocket(client); if (!this.cancel.Token.IsCancellationRequested) { NodeServerTrace.Error("The remote connecting failed to send a message within 10 seconds, dropping connection", null); } } catch (Exception ex) { if (this.cancel.IsCancellationRequested) { return; } if (client == null) { NodeServerTrace.Error("Error while accepting connection ", ex); Thread.Sleep(3000); } else { Utils.SafeCloseSocket(client); NodeServerTrace.Error("Invalid message received from the remote connecting peer", ex); } } this.BeginAccept(); } }
public async Task Connect(NetworkInfo networkInfo) { IPAddress ipAddress = null; WireSerialization.Instance.Magic = networkInfo.Magic; NodeServerTrace.Information($"Magic is {networkInfo.Magic}"); var natManager = new NATManager(networkInfo.DefaultPort); #if DEBUG if (networkInfo.IsLANHost) { ipAddress = natManager.InternalIPAddress ?? IPAddress.Loopback; networkInfo.PeersToFind = 0; } else if (networkInfo.IsLANClient) { var ipAddressStr = (natManager.InternalIPAddress ?? IPAddress.Loopback).ToString(); networkInfo.PeersToFind = 1; if (networkInfo.Seeds.Count == 0 && !networkInfo.Seeds.Contains(ipAddressStr)) { networkInfo.Seeds.Add(ipAddressStr); } } else #endif if (!string.IsNullOrEmpty(networkInfo.ExternalIPAddress)) { ipAddress = IPAddress.Parse(networkInfo.ExternalIPAddress); } else if (networkInfo.DisableUPnP) { StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Disabled; } else { StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Initializing; await natManager.Init(); if (natManager.DeviceFound && natManager.Mapped.Value && natManager.ExternalIPVerified.HasValue && natManager.ExternalIPVerified.Value) { StatusMessageProducer.OutboundStatus = OutboundStatusEnum.HasValidAddress; ipAddress = natManager.ExternalIPAddress; } else { StatusMessageProducer.OutboundStatus = OutboundStatusEnum.HasInvalidAddress; } } _BroadcastHubBehavior = new BroadcastHubBehavior(); _MinerBehavior = new MinerBehavior(); _NodeConnectionParameters.TemplateBehaviors.Add(_BroadcastHubBehavior); _NodeConnectionParameters.TemplateBehaviors.Add(_MinerBehavior); _NodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(_BlockChain, _BroadcastHubBehavior.BroadcastHub)); _NodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(_BlockChain)); AddressManagerBehavior.GetAddrman(_NodeConnectionParameters).PeersToFind = networkInfo.PeersToFind; if (ipAddress != null) { _NodeConnectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>().Mode = AddressManagerBehaviorMode.AdvertizeDiscover; //parameters.Advertize = true; _NodeConnectionParameters.AddressFrom = new System.Net.IPEndPoint(ipAddress, networkInfo.DefaultPort); } else { _NodeConnectionParameters.TemplateBehaviors.Find <AddressManagerBehavior>().Mode = AddressManagerBehaviorMode.Discover; } if (ipAddress != null) { _Server = new Server(ipAddress, networkInfo, _NodeConnectionParameters); OwnResource(_Server); if (_Server.Start()) { NodeServerTrace.Information($"Server started at {ipAddress}:{networkInfo.DefaultPort}"); StatusMessageProducer.OutboundStatus = OutboundStatusEnum.Accepting; } else { NodeServerTrace.Information($"Could not start server at {ipAddress}:{networkInfo.DefaultPort}"); } } if (networkInfo.Seeds.Count == 0) { NodeServerTrace.Information("No seeds defined"); } else { _NodesGroup = new NodesGroup(networkInfo, _NodeConnectionParameters); OwnResource(_NodesGroup); _NodesGroup.AllowSameGroup = true; //TODO _NodesGroup.MaximumNodeConnection = networkInfo.MaximumNodeConnection; #if TRACE _NodesGroup.ConnectedNodes.Added += (object sender, NodeEventArgs e) => { NodeServerTrace.Information("Peer found: " + e.Node.RemoteSocketAddress + ":" + e.Node.RemoteSocketPort); }; #endif _NodesGroup.Connect(); } }
void AttachedNode_MessageReceived(Node node, IncomingMessage message) { message.IfPayloadIs <Types.Block>(async bk => { var result = await new HandleBlockAction(bk).Publish(); switch (result.BkResultEnum) { case BlockChain.BlockVerificationHelper.BkResultEnum.Accepted: foreach (var other in Nodes) { if (other != AttachedNode && other.State == NodeState.HandShaked) { other.SendMessageAsync(bk); } } break; case BlockChain.BlockVerificationHelper.BkResultEnum.AcceptedOrphan: StatusMessageProducer.LastOrphan = bk.header.blockNumber; node.SendMessageAsync(new GetDataPayload(new InventoryVector[] { new InventoryVector(InventoryType.MSG_BLOCK, result.MissingParent) })); break; case BlockChain.BlockVerificationHelper.BkResultEnum.Rejected: if (result.MissingParent != null) { node.SendMessageAsync(new GetDataPayload(new InventoryVector[] { new InventoryVector(InventoryType.MSG_BLOCK, result.MissingParent) })); } //TODO: refine possible state (don't reject blocks that were requested by GetTip; reply with DUPLICATE instead of INVALID, ...) node.SendMessageAsync(new RejectPayload() { Hash = Consensus.Merkle.blockHeaderHasher.Invoke(bk.header), Code = RejectCode.INVALID, Message = "bk" }); break; } }); message.IfPayloadIs <GetTipPayload>(getTip => { var tip = _BlockChain.Tip; if (tip != null) { var bk = new GetBlockAction() { BkHash = tip.Key }.Publish().Result; if (bk != null) { NodeServerTrace.Information("Sending tip: " + tip.Value.header.blockNumber); node.SendMessageAsync(bk); } else { NodeServerTrace.Information("Missing or invalid tip block requested"); } } else { NodeServerTrace.Information("No tip to send"); } }); message.IfPayloadIs <GetDataPayload>(getData => { foreach (var inventory in getData.Inventory.Where(i => i.Type == InventoryType.MSG_BLOCK)) { var bk = new GetBlockAction() { BkHash = inventory.Hash }.Publish().Result; if (bk != null) { NodeServerTrace.Information("Sending block: " + bk.header.blockNumber); node.SendMessageAsync(bk); } else { NodeServerTrace.Information("Missing or invalid block requested"); } } }); }