public DistributedHost( IWorkQueue workQueue, ushort listenPort, bool isListener = true, int disconnectTimeout = -1, INetLogger logger = null) { Contract.Requires(listenPort != 0); ListenPort = listenPort; this.workQueue = workQueue; this.logger = logger; // determine our IP // hat tip https://stackoverflow.com/questions/6803073/get-local-ip-address IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); IPAddress ipv4Address = host .AddressList .FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork); SocketAddress = new SerializedSocketAddress(new IPEndPoint(ipv4Address, listenPort).Serialize()); netManager = new NetManager(new Listener(this)) { BroadcastReceiveEnabled = true, UnconnectedMessagesEnabled = true }; if (disconnectTimeout != -1) { netManager.DisconnectTimeout = disconnectTimeout; } netPacketProcessor = new NetPacketProcessor(); RegisterType <SerializedSocketAddress>(); RegisterType <DistributedId>(); netPacketProcessor.SubscribeReusable <AnnounceMessage, IPEndPoint>(OnAnnounceReceived); netPacketProcessor.SubscribeReusable <AnnounceResponseMessage, IPEndPoint>(OnAnnounceResponseReceived); netDataWriter = new NetDataWriter(); bool managerStarted; if (isListener) { managerStarted = netManager.Start(ListenPort); } else { managerStarted = netManager.Start(); } if (!managerStarted) { throw new PeerException("Could not start netManager"); } }
/// <summary> /// Get the proxies that are owned by this peer. /// </summary> public IReadOnlyDictionary <DistributedId, IDistributedObject> ProxiesForPeer(SerializedSocketAddress serializedSocketAddress) { Contract.Requires(netManager.ConnectedPeerList.Any(peer => { SerializedSocketAddress peerAddress = new SerializedSocketAddress(peer); bool addressesAreEqual = peerAddress.Equals(serializedSocketAddress); return(addressesAreEqual); })); Contract.Requires(proxies.ContainsKey(serializedSocketAddress)); return(proxies[serializedSocketAddress]); }
/// <summary> /// Handle a disconnected peer by deleting all that peer's proxies' local objects, and dropping /// all the proxies. /// </summary> public void OnPeerDisconnected(NetPeer netPeer, DisconnectInfo disconnectInfo) { SerializedSocketAddress peerAddress = new SerializedSocketAddress(netPeer); if (Host.proxies.TryGetValue(peerAddress, out Dictionary <DistributedId, IDistributedObject> peerObjects)) { // detach them all foreach (IDistributedObject proxy in peerObjects.Values) { proxy.OnDetach(); } // and drop the whole collection of proxies Host.proxies.Remove(peerAddress); } }
/// <summary> /// An announcement has been received (via broadcast); react accordingly. /// </summary> private void OnAnnounceReceived(AnnounceMessage message, IPEndPoint endpoint) { // heed only ipv4 for now... TBD what to do about this if (endpoint.AddressFamily == AddressFamily.InterNetwork) { // is this actually our own announcement!? SerializedSocketAddress incomingAddress = new SerializedSocketAddress(endpoint.Serialize()); if (incomingAddress == this.SocketAddress) { // ignore this, we're talking to ourselves return; } PeerAnnounceCount++; // do we know this peer already? // (could happen in race scenario) if (netManager.ConnectedPeerList.Any(peer => peer.EndPoint.Equals(endpoint))) { return; } // did we already respond to this peer? if (AnnouncedEndPoints.Contains(endpoint)) { return; } // did this peer know us already? (typical scenario given re-announcements) if (message.KnownPeers.Contains(SocketAddress)) { return; } logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.OnAnnounceReceived({endpoint}) -- responding. {ConnectionsStatusString()}]"); // send announce response AnnounceResponseMessage response = new AnnounceResponseMessage { }; SendUnconnectedMessage(response, endpoint); } }
private void OnDelete(NetPeer netPeer, DistributedId id, bool isRequest) { SerializedSocketAddress peerAddress = new SerializedSocketAddress(netPeer); if (isRequest) { // owner id may or may not still exist; it's OK if it doesn't. if (!owners.ContainsKey(id)) { // do nothing; ignore the delete request altogether } else { // we will accept this request... for testing purposes. // TBD if this is the right thing in general! IDistributedObject distributedObject = owners[id]; // and tell all proxies foreach (NetPeer proxyPeer in NetPeers) { distributedObject.DistributedType.SendDeleteMessageInternal(proxyPeer, false); } owners.Remove(id); distributedObject.OnDelete(); } } else { // this is an authoritative delete message from the owner. // we expect strong consistency here so the id should still exist. Contract.Requires(proxies[peerAddress].ContainsKey(id)); IDistributedObject proxy = proxies[peerAddress][id]; proxies[peerAddress].Remove(id); proxy.Delete(); } }
/// <summary> /// This is a new proxy being created on this peer, owned by netPeer. /// </summary> private void AddProxy(SerializedSocketAddress peerAddress, IDistributedObject proxy) { Contract.Requires(!proxy.IsOwner); proxies[peerAddress].Add(proxy.Id, proxy); }