/// <summary> /// Instantiate a new PeerChunkAvailabilityUpdate /// </summary> /// <param name="sourceNetworkIdentifier">The source network identifier</param> /// <param name="itemCheckSum">The related DFS item checksum</param> /// <param name="chunkFlags">The chunk availability flags </param> public PeerChunkAvailabilityUpdate(string sourceNetworkIdentifier, string itemCheckSum, ChunkFlags chunkFlags) { this.SourceNetworkIdentifier = sourceNetworkIdentifier; this.ItemCheckSum = itemCheckSum; this.ChunkFlags = chunkFlags; }
/// <summary> /// Updates local chunk flags with those provided. /// </summary> /// <param name="latestChunkFlags">The new chunk flags</param> public void UpdateFlags(ChunkFlags latestChunkFlags) { flags0 = latestChunkFlags.flags0; flags1 = latestChunkFlags.flags1; flags2 = latestChunkFlags.flags2; flags3 = latestChunkFlags.flags3; }
/// <summary> /// Initialise a new PeerInfo /// </summary> /// <param name="peerConnectionInfo">All ConnectionInfos corresponding with this peer</param> /// <param name="peerChunkFlags">The initial ChunkFlags for this peer</param> /// <param name="superPeer">True if this is a SuperPeer</param> public PeerInfo(List<ConnectionInfo> peerConnectionInfo, ChunkFlags peerChunkFlags, bool superPeer) { if (peerConnectionInfo.Count == 0) throw new ArgumentException("Provided peerConnectionInfo list must contain at least one element."); this.PeerNetworkIdentifier = peerConnectionInfo[0].NetworkIdentifier; if (this.PeerNetworkIdentifier == null || this.PeerNetworkIdentifier == ShortGuid.Empty) throw new Exception("PeerInfo PeerNetworkIdentifier should not be empty."); foreach (ConnectionInfo info in peerConnectionInfo) { if (info.NetworkIdentifier != this.PeerNetworkIdentifier) throw new Exception("The provided peerConnectionInfo contains more than one unique NetworkIdentifier."); //Add the necessary entries into status dictionaries IPEndPointBusyAnnounceTimeDict[info] = DateTime.Now; IPEndPointOnlineDict[info] = false; IPEndPointBusyDict[info] = false; IPEndPointTimeoutCountDict[info] = 0; } this.PeerConnectionInfo = peerConnectionInfo; this.PeerChunkFlags = peerChunkFlags; this.SuperPeer = superPeer; }
/// <summary> /// Adds or updates a peer to the local availability list. Useful for when a peer informs us of an updated availability. /// </summary> /// <param name="connectionInfo">The connectionInfo of the remote peer</param> /// <param name="latestChunkFlags">The new chunk flags</param> /// <param name="superPeer">True if this peer is a superPeer</param> /// <param name="setIPEndPointOnline">Set the relevant IPEndPoint online as a result of updating chunk flags</param> public void AddOrUpdateCachedPeerChunkFlags(ConnectionInfo connectionInfo, ChunkFlags latestChunkFlags, bool superPeer = false, bool setIPEndPointOnline = true) { if (connectionInfo.NetworkIdentifier == ShortGuid.Empty) throw new Exception("networkIdentifier should not be empty."); lock (peerLocker) { if (connectionInfo.ConnectionType != ConnectionType.TCP) throw new Exception("Only the TCP side of a DFS peer should be tracked."); //Extract the correct endpoint from the provided connectionInfo //If this is taken from a connection we are after the remoteEndPoint IPEndPoint endPointToUse = null; if (((IPEndPoint)connectionInfo.RemoteEndPoint).Address == IPAddress.Any || ((IPEndPoint)connectionInfo.RemoteEndPoint).Address == IPAddress.IPv6Any) endPointToUse = (IPEndPoint)connectionInfo.LocalEndPoint; else endPointToUse = (IPEndPoint)connectionInfo.RemoteEndPoint; string endPointToUseString = endPointToUse.ToString(); //We can only add a peer if it is listening correctly if (endPointToUse.Port <= DFS.MaxTargetLocalPort && endPointToUse.Port >= DFS.MinTargetLocalPort) { //Ensure the endpoint is correctly recorded RemoveOldPeerAtEndPoint(connectionInfo.NetworkIdentifier, endPointToUse); //If we have an existing record of this peer if (peerAvailabilityByNetworkIdentifierDict.ContainsKey(connectionInfo.NetworkIdentifier)) { //If the existing peerInfo is not aware of this endPoint if (!peerAvailabilityByNetworkIdentifierDict[connectionInfo.NetworkIdentifier].PeerContainsIPEndPoint(connectionInfo.NetworkIdentifier, endPointToUse)) { //Add the information to the peerInfo and local index peerAvailabilityByNetworkIdentifierDict[connectionInfo.NetworkIdentifier].AddPeerIPEndPoint(connectionInfo.NetworkIdentifier, endPointToUse); peerEndPointToNetworkIdentifier[endPointToUseString] = connectionInfo.NetworkIdentifier; } //Finally update the chunk flags peerAvailabilityByNetworkIdentifierDict[connectionInfo.NetworkIdentifier].PeerChunkFlags.UpdateFlags(latestChunkFlags); if (DFS.loggingEnabled) DFS.Logger.Trace("Updated existing chunk flags for " + connectionInfo + " [" + latestChunkFlags.NumCompletedChunks() + "]."); } else { //If we don't know anything about this peer we add it to our local swarm availability //We used comms to get any existing connections to the peer //We have to create new ConnectionInfo in the select as we need to correctly set the "LOCAL IPEndPoint" when passing to new PeerInfo() List<ConnectionInfo> peerConnectionInfos = (from current in NetworkComms.GetExistingConnection(connectionInfo.NetworkIdentifier, ConnectionType.TCP) select new ConnectionInfo(ConnectionType.TCP, current.ConnectionInfo.NetworkIdentifier, current.ConnectionInfo.RemoteEndPoint, true)).ToList(); //Don't forget to add the originating info if it was not pulled out from above ConnectionInfo originatingConnectionInfo = new ConnectionInfo(ConnectionType.TCP, connectionInfo.NetworkIdentifier, endPointToUse, true); if (!peerConnectionInfos.Contains(originatingConnectionInfo)) peerConnectionInfos.Add(originatingConnectionInfo); peerAvailabilityByNetworkIdentifierDict.Add(connectionInfo.NetworkIdentifier, new PeerInfo(peerConnectionInfos, latestChunkFlags, superPeer)); //We finish by adding the endPoint references foreach (ConnectionInfo connInfo in peerConnectionInfos) peerEndPointToNetworkIdentifier[connInfo.LocalEndPoint.ToString()] = connectionInfo.NetworkIdentifier; if (DFS.loggingEnabled) DFS.Logger.Trace("Added new chunk flags for " + connectionInfo); } if (setIPEndPointOnline) //By updating cached peer chunk flags we set the peer as being online peerAvailabilityByNetworkIdentifierDict[connectionInfo.NetworkIdentifier].SetPeerIPEndPointOnlineStatus(connectionInfo.NetworkIdentifier, endPointToUse, true); //We will trigger the alive peers event when we have at least a third of the existing peers if (!alivePeersReceivedEvent.WaitOne(0)) { int numOnlinePeers = (from current in peerAvailabilityByNetworkIdentifierDict.Values where current.HasAtleastOneOnlineIPEndPoint() select current).Count(); if (numOnlinePeers >= DFS.MaxTotalItemRequests || numOnlinePeers > peerAvailabilityByNetworkIdentifierDict.Count / 3.0) alivePeersReceivedEvent.Set(); } } else throw new Exception("Attempted to AddOrUpdateCachedPeerChunkFlags for client which was not listening or was using port outside the valid DFS range. Provided connectionInfo: " + connectionInfo + ". EndPointToUse:" + endPointToUse); //LogTools.LogException("Attempted to AddOrUpdateCachedPeerChunkFlags for client which was not listening or was using port outside the valid DFS range.", "PeerChunkFlagsUpdateError", "IP:" + endPointToUse.Address.ToString() + ", Port:" + endPointToUse.Port); } }