public void Failed(Message.Message.MessageType type) { var responseMessage = DispatchHandler.CreateResponseMessage(_requestMessage, type, _peerBeanMaster.ServerPeerAddress); _dispatcher.Respond(_ctx, responseMessage); }
/// <summary> /// Looks for a route to the location key given in the routing builder. /// </summary> /// <param name="routingBuilder">All relevant information for the routing process.</param> /// <param name="type">The type of the routing. (4 types)</param> /// <param name="cc">The channel creator.</param> /// <returns>A task object that is set to complete if the route has been found.</returns> public TcsRouting Route(RoutingBuilder routingBuilder, Message.Message.MessageType type, ChannelCreator cc) { // for bad distribution, use large #noNewInformation ICollection <PeerAddress> startPeers = _peerBean.PeerMap.ClosePeers(routingBuilder.LocationKey, routingBuilder.Parallel * 2); return(Routing(startPeers, routingBuilder, type, cc)); }
/// <summary> /// Creates a RequestHandler. /// </summary> /// <param name="remotePeer">The destination peer.</param> /// <param name="type">The type of the request.</param> /// <param name="configuration"></param> /// <returns></returns> private RequestHandler CreateHandler(PeerAddress remotePeer, Message.Message.MessageType type, IConnectionConfiguration configuration) { // .NET-specific: // 1. use TCS<Message> instead of FutureResponse // 2. store message as the TCS's AsyncState var message = CreateRequestMessage(remotePeer, Rpc.Commands.Ping.GetNr(), type); var tcsResponse = new TaskCompletionSource <Message.Message>(message); return(new RequestHandler(tcsResponse, PeerBean, ConnectionBean, configuration)); }
public static Message.Message CreateResponseMessage(Message.Message requestMessage, Message.Message.MessageType replyType, PeerAddress peerAddress) { // this will have the ports >40'000 that we need to know for sending the reply return(new Message.Message() .SetSenderSocket(requestMessage.SenderSocket) .SetRecipientSocket(requestMessage.RecipientSocket) .SetRecipient(requestMessage.Sender) .SetSender(peerAddress) .SetCommand(requestMessage.Command) .SetType(replyType) .SetVersion(requestMessage.Version) .SetMessageId(requestMessage.MessageId) .SetIsUdp(requestMessage.IsUdp)); }
private void RoutingRec(RoutingBuilder routingBuilder, RoutingMechanism routingMechanism, Message.Message.MessageType type, ChannelCreator channelCreator) { var randomSearch = routingBuilder.LocationKey == null; var active = 0; for (var i = 0; i < routingMechanism.Parallel; i++) { if (routingMechanism.GetTcsResponse(i) == null && !routingMechanism.IsStopCreatingNewFutures) { PeerAddress next; if (randomSearch) { next = routingMechanism.PollRandomInQueueToAsk(_rnd); } else { next = routingMechanism.PollFirstInQueueToAsk(); } if (next != null) { routingMechanism.AddToAlreadyAsked(next); active++; // If we search for a random peer, then the peer should // return the address farest away. var locationKey2 = randomSearch ? next.PeerId.Xor(Number160.MaxValue) : routingBuilder.LocationKey; routingBuilder.LocationKey = locationKey2; // routing is per default UDP, don't show warning if the other TCP/UDP is used // TODO find .NET-specific way to show sanity check warning routingMechanism.SetTcsResponse(i, _neighbors.CloseNeighborsTcs(next, routingBuilder.SearchValues(), type, channelCreator, routingBuilder)); Logger.Debug("Get close neighbours: {0} on {1}.", next, i); } } else if (routingMechanism.GetTcsResponse(i) != null) { Logger.Debug("Activity on {0}.", i); active++; } } if (active == 0) { Logger.Debug("No activity, closing."); routingMechanism.SetNeighbors(routingBuilder); routingMechanism.Cancel(); return; } // .NET-specific: // TODO move to TcsForkJoin as separate c'tor? var extractedTasks = new Task <Message.Message> [routingMechanism.TcsResponses.Length]; for (int i = 0; i < routingMechanism.TcsResponses.Length; i++) { extractedTasks[i] = routingMechanism.GetTcsResponse(i) != null?routingMechanism.GetTcsResponse(i).Task : null; } var volatileArray = new VolatileReferenceArray <Task <Message.Message> >(extractedTasks); bool last = active == 1; var tcsForkJoin = new TcsForkJoin <Task <Message.Message> >(1, false, volatileArray); tcsForkJoin.Task.ContinueWith(tfj => { bool finished; if (!tfj.IsFaulted) { var lastResponse = tcsForkJoin.Last.Result; var remotePeer = lastResponse.Sender; routingMechanism.AddPotentialHits(remotePeer); var newNeighbors = lastResponse.NeighborsSet(0).Neighbors; var resultSize = lastResponse.IntAt(0); var keyDigest = lastResponse.Key(0); var contentDigest = lastResponse.Key(1); var digestBean = new DigestInfo(keyDigest, contentDigest, resultSize); Logger.Debug("Peer ({0}) {1} reported {2} in message {3}.", (digestBean.Size > 0 ? "direct" : "none"), remotePeer, newNeighbors.Count, lastResponse); finished = routingMechanism.EvaluateSuccess(remotePeer, digestBean, newNeighbors, last, routingBuilder.LocationKey); Logger.Debug("Routing finished {0} / {1}.", finished, routingMechanism.IsStopCreatingNewFutures); } else { // if it failed but the failed is the closest one, it is good to try again, // since the peer might just be busy Logger.Debug("Routing error {0}.", tfj.Exception); finished = routingMechanism.EvaluateFailed(); routingMechanism.IsStopCreatingNewFutures = finished; } if (finished) { Logger.Debug("Routing finished. Direct hits: {0}. Potential hits: {1}.", routingMechanism.DirectHits.Count, routingMechanism.PotentialHits.Count); routingMechanism.SetNeighbors(routingBuilder); routingMechanism.Cancel(); // stop all operations, as we are finished, no need to go further } else { RoutingRec(routingBuilder, routingMechanism, type, channelCreator); } }); }
/// <summary> /// Looks for a route to the given peer address. /// </summary> /// <param name="peerAddresses">Nodes that should be asked first for a route.</param> /// <param name="routingBuilder"></param> /// <param name="type"></param> /// <param name="cc"></param> /// <returns>A task object that is set to complete if the route has been found.</returns> private TcsRouting Routing(ICollection <PeerAddress> peerAddresses, RoutingBuilder routingBuilder, Message.Message.MessageType type, ChannelCreator cc) { try { if (peerAddresses == null) { throw new ArgumentException("Some nodes/addresses need to be specified."); } bool randomSearch = routingBuilder.LocationKey == null; IComparer <PeerAddress> comparer; if (randomSearch) { comparer = _peerBean.PeerMap.CreateComparer(); } else { comparer = PeerMap.CreateComparer(routingBuilder.LocationKey); } var queueToAsk = new SortedSet <PeerAddress>(comparer); var alreadyAsked = new SortedSet <PeerAddress>(comparer); // As presented by Kazuyuki Shudo at AIMS 2009, it is better to ask random // peers with the data than ask peers that are ordered by distance. // -> this balances load var directHits = new SortedDictionary <PeerAddress, DigestInfo>(comparer); var potentialHits = new SortedSet <PeerAddress>(comparer); // fill initially queueToAsk.AddAll(peerAddresses); alreadyAsked.Add(_peerBean.ServerPeerAddress); potentialHits.Add(_peerBean.ServerPeerAddress); // domain key can be null if we bootstrap if (type == Message.Message.MessageType.Request2 && routingBuilder.DomainKey != null && !randomSearch && _peerBean.DigestStorage != null) { Number640 from; Number640 to; if (routingBuilder.From != null && routingBuilder.To != null) { from = routingBuilder.From; to = routingBuilder.To; } else if (routingBuilder.ContentKey == null) { from = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, Number160.Zero, Number160.Zero); to = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, Number160.MaxValue, Number160.MaxValue); } else { from = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, routingBuilder.ContentKey, Number160.Zero); to = new Number640(routingBuilder.LocationKey, routingBuilder.DomainKey, routingBuilder.ContentKey, Number160.MaxValue); } var digestBean = _peerBean.DigestStorage.Digest(from, to, -1, true); if (digestBean.Size > 0) { directHits.Add(_peerBean.ServerPeerAddress, digestBean); } } else if (type == Message.Message.MessageType.Request3 && !randomSearch && _peerBean.DigestTracker != null) { var digestInfo = _peerBean.DigestTracker.Digest(routingBuilder.LocationKey, routingBuilder.DomainKey, routingBuilder.ContentKey); // we always put ourselfs to the tracker list, so we need to check // if we know also other peers on our trackers if (digestInfo.Size > 0) { directHits.Add(_peerBean.ServerPeerAddress, digestInfo); } } var tcsRouting = new TcsRouting(); if (peerAddresses.Count == 0) { tcsRouting.SetNeighbors(directHits, potentialHits, alreadyAsked, routingBuilder.IsBootstrap, false); } else { // If a peer bootstraps to itself, then the size of peer addresses is 1 // and it contains itself. Check for that because we need to know if we // are routing, bootstrapping and bootstrapping to ourselfs, to return // the correct status for the task. var isRoutingOnlyToSelf = peerAddresses.Count == 1 && peerAddresses.First().Equals(_peerBean.ServerPeerAddress); var routingMechanism = routingBuilder.CreateRoutingMechanism(tcsRouting); routingMechanism.SetQueueToAsk(queueToAsk); routingMechanism.SetPotentialHits(potentialHits); routingMechanism.SetDirectHits(directHits); routingMechanism.SetAlreadyAsked(alreadyAsked); routingBuilder.SetIsRoutingOnlyToSelf(isRoutingOnlyToSelf); RoutingRec(routingBuilder, routingMechanism, type, cc); } return(tcsRouting); } catch (Exception ex) { Logger.Error("An exception occurred during routing.", ex); throw; } }
/// <summary> /// Creates a response requestMessage and fills it with peer bean and connection bean parameters. /// </summary> /// <param name="requestMessage">The request requestMessage.</param> /// <param name="replyType">The type of the reply.</param> /// <returns>The response requestMessage.</returns> public Message.Message CreateResponseMessage(Message.Message requestMessage, Message.Message.MessageType replyType) { return(CreateResponseMessage(requestMessage, replyType, PeerBean.ServerPeerAddress)); }
/// <summary> /// Creates a request requestMessage and fills it with peer bean and connection bean parameters. /// </summary> /// <param name="recipient">The recipient of this requestMessage.</param> /// <param name="name">The command type.</param> /// <param name="type">The request type.</param> /// <returns>The created request requestMessage.</returns> public Message.Message CreateRequestMessage(PeerAddress recipient, sbyte name, Message.Message.MessageType type) { return(new Message.Message() .SetRecipient(recipient) .SetSender(PeerBean.ServerPeerAddress) .SetCommand(name) .SetType(type) .SetVersion(ConnectionBean.P2PId)); }
/// <summary> /// .NET-specific: Used for DistributedRouting only. /// </summary> internal TaskCompletionSource <Message.Message> CloseNeighborsTcs(PeerAddress remotePeer, SearchValues searchValues, Message.Message.MessageType type, ChannelCreator channelCreator, IConnectionConfiguration configuration) { var message = CreateRequestMessage(remotePeer, Rpc.Commands.Neighbor.GetNr(), type); if (!message.IsRequest()) { throw new ArgumentException("The type must be a request."); } message.SetKey(searchValues.LocationKey); message.SetKey(searchValues.DomainKey ?? Number160.Zero); if (searchValues.From != null && searchValues.To != null) { ICollection <Number640> collection = new List <Number640>(); collection.Add(searchValues.From); collection.Add(searchValues.To); var keyCollection = new KeyCollection(collection); message.SetKeyCollection(keyCollection); } else { if (searchValues.ContentKey != null) { message.SetKey(searchValues.ContentKey); } if (searchValues.KeyBloomFilter != null) { message.SetBloomFilter(searchValues.KeyBloomFilter); } if (searchValues.ContentBloomFilter != null) { message.SetBloomFilter(searchValues.ContentBloomFilter); } } return(Send(message, configuration, channelCreator)); }
/// <summary> /// Requests close neighbors from the remote peer. The remote peer may indicate if the /// data is present on that peer. This is an RPC. /// </summary> /// <param name="remotePeer">The remote peer to send this request to.</param> /// <param name="searchValues">The values to search for in the storage.</param> /// <param name="type">The type of the neighbor request: /// - Request1 for Neighbors means check for Put (no digest) for tracker and storage. /// - Request2 for Neighbors means check for Get (with digest) for storage. /// - Request3 for Neighbors means check for Get (with digest) for tracker. /// - Request4 for Neighbors means check for Put (with digest) for task.</param> /// <param name="channelCreator">The channel creator that creates connections.</param> /// <param name="configuration">The client-side connection configuration.</param> /// <returns>The future response message.</returns> public Task <Message.Message> CloseNeighborsAsync(PeerAddress remotePeer, SearchValues searchValues, Message.Message.MessageType type, ChannelCreator channelCreator, IConnectionConfiguration configuration) { var tcsResponse = CloseNeighborsTcs(remotePeer, searchValues, type, channelCreator, configuration); return(tcsResponse.Task); }