示例#1
0
        /// <summary>
        /// Sends a UDP message and expects a response.
        /// </summary>
        /// <param name="channelCreator">The channel creator will create a UDP connection.</param>
        /// <returns>The future task that was added in the constructor.</returns>
        public Task <Message.Message> SendUdpAsync(ChannelCreator channelCreator)
        {
            // so far, everything is sync -> invoke async / new thread
            var sendTask = ConnectionBean.Sender.SendUdpAsync(this, _tcsResponse, _message, channelCreator, IdleUdpSeconds, false);

            return(ExecuteAsync(sendTask));
        }
示例#2
0
        /// <summary>
        /// Sends a TCP message and expects a response.
        /// </summary>
        /// <param name="channelCreator">The channel creator will create a TCP connection.</param>
        /// <param name="peerConnection"></param>
        /// <returns>The future task that was added in the constructor.</returns>
        public Task <Message.Message> SendTcpAsync(ChannelCreator channelCreator, PeerConnection peerConnection)
        {
            var sendTask = ConnectionBean.Sender.SendTcpAsync(this, _tcsResponse, _message, channelCreator, IdleTcpSeconds,
                                                              ConnectionTimeoutTcpMillis, peerConnection);

            return(ExecuteAsync(sendTask));
        }
        /// <summary>
        /// Bootstraps to the given peer addresses. I.e., looking for near nodes.
        /// </summary>
        /// <param name="peerAddresses">The node to which bootstrap should be performed to.</param>
        /// <param name="routingBuilder">All relevant information for the routing process.</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 Task<Pair<TcsRouting, TcsRouting>> Bootstrap(ICollection<PeerAddress> peerAddresses,
            RoutingBuilder routingBuilder, ChannelCreator cc)
        {
            // search close peers
            Logger.Debug("Bootstrap to {0}.", Convenient.ToString(peerAddresses));
            var tcsDone = new TaskCompletionSource<Pair<TcsRouting, TcsRouting>>();

            // first, we find close peers to us
            routingBuilder.IsBootstrap = true;

            var tcsRouting0 = Routing(peerAddresses, routingBuilder, Message.Message.MessageType.Request1, cc);
            // we need to know other peers as well
            // this is important if this peer is passive and only replies on requests from other peers
            tcsRouting0.Task.ContinueWith(taskRouting0 =>
            {
                if (!taskRouting0.IsFaulted)
                {
                    // setting this to null causes to search for a random number
                    routingBuilder.LocationKey = null;
                    var tcsRouting1 = Routing(peerAddresses, routingBuilder, Message.Message.MessageType.Request1, cc);
                    tcsRouting1.Task.ContinueWith(taskRouting1 =>
                    {
                        var pair = new Pair<TcsRouting, TcsRouting>(tcsRouting0, tcsRouting1);
                        tcsDone.SetResult(pair);
                    });
                }
                else
                {
                    tcsDone.SetException(taskRouting0.TryGetException());
                }
            });

            return tcsDone.Task;
        }
示例#4
0
 public void AddTcsDhtReleaseListener(ChannelCreator channelCreator)
 {
     Task.ContinueWith(tDht =>
     {
         FutureRequests.Task.ContinueWith(tcsForkJoin =>
         {
             channelCreator.ShutdownAsync();
         });
     });
 }
示例#5
0
 /// <summary>
 /// If we don't have an open TCP connection, we first need a channel creator to open a channel.
 /// </summary>
 /// <param name="remotePeer">The remote peer to connect to.</param>
 /// <param name="cc">The channel creator where we can open a TCP connection.</param>
 /// <param name="heartBeatMillis"></param>
 public PeerConnection(PeerAddress remotePeer, ChannelCreator cc, int heartBeatMillis)
 {
     RemotePeer      = remotePeer;
     ChannelCreator  = cc;
     HeartBeatMillis = heartBeatMillis;
     _initiator      = true;
     _oneConnection  = new Semaphore(1, 1);
     _map            = new Dictionary <TaskCompletionSource <ChannelCreator>, TaskCompletionSource <Message.Message> >();
     _tcsClose       = new TaskCompletionSource <object>();
 }
示例#6
0
        public Task<Message.Message> SendAsync(PeerAddress remotePeer, ISendDirectBuilder sendDirectBuilder,
            ChannelCreator channelCreator)
        {
            var requestHandler = SendInternal(remotePeer, sendDirectBuilder);

            if (!sendDirectBuilder.IsForceUdp)
            {
                return requestHandler.SendTcpAsync(channelCreator);
            }
            return requestHandler.SendUdpAsync(channelCreator);
        }
示例#7
0
 private PeerConnection(Semaphore oneConnection, PeerAddress remotePeer, ChannelCreator cc, bool initiator,
                        IDictionary <TaskCompletionSource <ChannelCreator>, TaskCompletionSource <Message.Message> > map,
                        TaskCompletionSource <object> tcsClose, int heartBeatMillis, ITcpChannel channel)
 {
     _oneConnection  = oneConnection;
     RemotePeer      = remotePeer;
     ChannelCreator  = cc;
     _initiator      = initiator;
     _map            = map;
     _tcsClose       = tcsClose;
     HeartBeatMillis = heartBeatMillis;
     _channel        = channel;
 }
示例#8
0
        /// <summary>
        /// Sends a message via TCP.
        /// </summary>
        /// <param name="handler">The handler to deal with the response message.</param>
        /// <param name="tcsResponse">The TCS for the response message. (FutureResponse equivalent.)</param>
        /// <param name="message">The message to send.</param>
        /// <param name="channelCreator">The channel creator for the TCP channel.</param>
        /// <param name="idleTcpSeconds">The idle time until message fail.</param>
        /// <param name="connectTimeoutMillis">The idle time for the connection setup.</param>
        /// <param name="peerConnection"></param>
        /// <returns></returns>
        public async Task SendTcpAsync(IInboundHandler handler, TaskCompletionSource <Message.Message> tcsResponse,
                                       Message.Message message, ChannelCreator channelCreator, int idleTcpSeconds, int connectTimeoutMillis,
                                       PeerConnection peerConnection)
        {
            // no need to continue if already finished
            if (tcsResponse.Task.IsCompleted)
            {
                return;
            }
            RemovePeerIfFailed(tcsResponse, message);

            bool isFireAndForget = handler == null;

            // we need to set the neighbors if we use relays
            if (message.Sender.IsRelayed && message.Sender.PeerSocketAddresses.Count != 0)
            {
                message.SetPeerSocketAddresses(message.Sender.PeerSocketAddresses);
            }
            if (peerConnection != null && peerConnection.Channel != null && peerConnection.Channel.IsOpen)
            {
                var channel = SendTcpPeerConnection(peerConnection, handler, channelCreator, tcsResponse);
                await AfterConnectAsync(tcsResponse, message, channel, isFireAndForget);
            }
            else if (channelCreator != null)
            {
                var timeoutHandler = CreateTimeoutHandler(tcsResponse, idleTcpSeconds, handler == null);
                // check relay
                if (message.Recipient.IsRelayed)
                {
                    // check if reverse connection is possible
                    if (!message.Sender.IsRelayed)
                    {
                        await HandleRconAsync(handler, tcsResponse, message, channelCreator, connectTimeoutMillis, peerConnection,
                                              timeoutHandler);
                    }
                    else
                    {
                        await HandleRelayAsync(handler, tcsResponse, message, channelCreator, idleTcpSeconds, connectTimeoutMillis,
                                               peerConnection, timeoutHandler);
                    }
                }
                // normal connection
                else
                {
                    await ConnectAndSendAsync(handler, tcsResponse, channelCreator, connectTimeoutMillis, peerConnection,
                                              timeoutHandler, message);
                }
            }
        }
示例#9
0
        /// <summary>
        /// // TODO document
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="tcsResponse"></param>
        /// <param name="message"></param>
        /// <param name="channelCreator"></param>
        /// <param name="idleTcpSeconds"></param>
        /// <param name="connectTimeoutMillis"></param>
        /// <param name="peerConnection"></param>
        /// <param name="timeoutHandler"></param>
        private async Task HandleRelayAsync(IInboundHandler handler, TaskCompletionSource <Message.Message> tcsResponse,
                                            Message.Message message, ChannelCreator channelCreator, int idleTcpSeconds, int connectTimeoutMillis,
                                            PeerConnection peerConnection, TimeoutFactory timeoutHandler)
        {
            var   taskPingDone = PingFirst(message.Recipient.PeerSocketAddresses);
            await taskPingDone;

            if (!taskPingDone.IsFaulted)
            {
                var recipient = PeerSocketAddress.CreateSocketTcp(taskPingDone.Result);
                var channel   = SendTcpCreateChannel(recipient, channelCreator, peerConnection, handler,
                                                     timeoutHandler, connectTimeoutMillis);
                await AfterConnectAsync(tcsResponse, message, channel, handler == null);

                // TODO add this before AfterConnect?
                var   taskResponse = tcsResponse.Task;
                await taskResponse;
                if (taskResponse.IsFaulted)
                {
                    if (taskResponse.Result != null &&
                        taskResponse.Result.Type != Message.Message.MessageType.User1)
                    {
                        // "clearInactivePeerSocketAddress"
                        var tmp = new List <PeerSocketAddress>();
                        foreach (var psa in message.Recipient.PeerSocketAddresses)
                        {
                            if (psa != null)
                            {
                                if (!psa.Equals(taskPingDone.Result))
                                {
                                    tmp.Add(psa);
                                }
                            }
                        }
                        message.SetPeerSocketAddresses(tmp);

                        await SendTcpAsync(handler, tcsResponse, message, channelCreator, idleTcpSeconds,
                                           connectTimeoutMillis, peerConnection);
                    }
                }
            }
            else
            {
                // .NET-specific:
                tcsResponse.SetException(new TaskFailedException("No relay could be contacted. <-> " + taskPingDone.Exception));
            }
        }
示例#10
0
        /// <summary>
        /// Sends a message that indicates this peer is about to quit. This is an RPC.
        /// </summary>
        /// <param name="remotePeer">The remote peer to send this request.</param>
        /// <param name="shutdownBuilder">Used for the sign and force TCP flag. Set if the message should be signed.</param>
        /// <param name="channelCreator">The channel creator that creates connections.</param>
        /// <returns>The future response message.</returns>
        public Task<Message.Message> QuitAsync(PeerAddress remotePeer, ShutdownBuilder shutdownBuilder,
            ChannelCreator channelCreator)
        {
            var message = CreateRequestMessage(remotePeer, Rpc.Commands.Quit.GetNr(),
                Message.Message.MessageType.RequestFf1);
            if (shutdownBuilder.IsSign)
            {
                message.SetPublicKeyAndSign(shutdownBuilder.KeyPair);
            }

            var tcsResponse = new TaskCompletionSource<Message.Message>(message);
            var requestHandler = new RequestHandler(tcsResponse, PeerBean, ConnectionBean, shutdownBuilder);
            Logger.Debug("Send QUIT message {0}.", message);
            if (!shutdownBuilder.IsForceTcp)
            {
                return requestHandler.FireAndForgetUdpAsync(channelCreator);
            }
            return requestHandler.SendTcpAsync(channelCreator);
        }
示例#11
0
 public Task CloseAsync()
 {
     // cc is not null if we opened the connection
     if (ChannelCreator != null)
     {
         Logger.Debug("Close connection {0}. We were the initiator.", _channel);
         // maybe done on arrival? set close future in any case
         ChannelCreator.ShutdownAsync().ContinueWith(delegate
         {
             _tcsClose.SetResult(null); // complete
         });
     }
     else
     {
         // cc is null if it is an incoming connection
         // we can close it here or it will be closed when the dispatcher is shut down
         Logger.Debug("Close connection {0}. We are not the initiator.", _channel);
         _channel.Close();
     }
     return(_tcsClose.Task);
 }
示例#12
0
 /// <summary>
 /// Adds a channel creator to the set and also adds it to the shutdown listener.
 /// </summary>
 /// <param name="channelCreator"></param>
 private void AddToSet(ChannelCreator channelCreator)
 {
     channelCreator.ShutdownTask.ContinueWith(delegate
     {
         _readWriteLock.EnterReadLock();
         try
         {
             if (_shutdown)
             {
                 return;
             }
             //Console.WriteLine("Removing channel creator from set.");
             _channelCreators.Remove(channelCreator);
         }
         finally
         {
             _readWriteLock.ExitReadLock();
         }
     });
     _channelCreators.Add(channelCreator);
 }
示例#13
0
 public Task<Message.Message> SendAsync(PeerAddress remotePeer, BroadcastBuilder broadcastBuilder,
     ChannelCreator channelCreator, IConnectionConfiguration configuration)
 {
     var message = CreateRequestMessage(remotePeer, Rpc.Commands.Broadcast.GetNr(),
         Message.Message.MessageType.RequestFf1);
     message.SetIntValue(broadcastBuilder.HopCounter);
     message.SetKey(broadcastBuilder.MessageKey);
     if (broadcastBuilder.DataMap != null)
     {
         message.SetDataMap(new DataMap(broadcastBuilder.DataMap));
     }
     var tcsResponse = new TaskCompletionSource<Message.Message>(message);
     var requestHandler = new RequestHandler(tcsResponse, PeerBean, ConnectionBean, configuration);
     if (!broadcastBuilder.IsUdp)
     {
         return requestHandler.SendTcpAsync(channelCreator);
     }
     else
     {
         return requestHandler.FireAndForgetUdpAsync(channelCreator);
     }
 }
示例#14
0
        private ITcpClientChannel SendTcpCreateChannel(IPEndPoint recipient, ChannelCreator channelCreator,
                                                       PeerConnection peerConnection, IChannelHandler handler, TimeoutFactory timeoutHandler, int connectTimeoutMillis)
        {
            // create pipeline
            var handlers = new Dictionary <string, IChannelHandler>();

            if (timeoutHandler != null)
            {
                handlers.Add("timeout0", timeoutHandler.CreateIdleStateHandlerTomP2P());
                handlers.Add("timeout1", timeoutHandler.CreateTimeHandler());
            }
            handlers.Add("decoder", new TomP2PCumulationTcp(ChannelClientConfiguration.SignatureFactory));
            handlers.Add("encoder", new TomP2POutbound(false, ChannelClientConfiguration.SignatureFactory));
            if (peerConnection != null)
            {
                // we expect responses on this connection
                handlers.Add("dispatcher", _dispatcher);
            }
            if (timeoutHandler != null)
            {
                handlers.Add("handler", handler);
            }
            HeartBeat heartBeat = null;

            if (peerConnection != null)
            {
                heartBeat = new HeartBeat(peerConnection.HeartBeatMillis, PingBuilderFactory);
                handlers.Add("heartbeat", heartBeat);
            }

            var channel = channelCreator.CreateTcp(recipient, connectTimeoutMillis, handlers);

            if (peerConnection != null && channel != null)
            {
                peerConnection.SetChannel(channel);
                heartBeat.SetPeerConnection(peerConnection);
            }
            return(channel);
        }
示例#15
0
        /// <summary>
        /// This method initiates the reverse connection setup.
        /// It creates a new message and sends it via relay to the unreachable peer
        /// which then connects to this peer again. After the connect message from the
        /// unreachable peer, this peer will send the original message and its content
        /// directly.
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="tcsResponse"></param>
        /// <param name="message"></param>
        /// <param name="channelCreator"></param>
        /// <param name="connectTimeoutMillis"></param>
        /// <param name="peerConnection"></param>
        /// <param name="timeoutHandler"></param>
        private async Task HandleRconAsync(IInboundHandler handler, TaskCompletionSource <Message.Message> tcsResponse,
                                           Message.Message message, ChannelCreator channelCreator, int connectTimeoutMillis,
                                           PeerConnection peerConnection, TimeoutFactory timeoutHandler)
        {
            message.SetKeepAlive(true);

            Logger.Debug("Initiate reverse connection setup to peer with address {0}.", message.Recipient);
            var rconMessage = CreateRconMessage(message);

            // TODO works?
            // cache the original message until the connection is established
            _cachedRequests.AddOrUpdate(message.MessageId, tcsResponse, (i, source) => tcsResponse);

            // wait for response (whether the reverse connection setup was successful)
            var tcsRconResponse = new TaskCompletionSource <Message.Message>(rconMessage);

            // .NET-specific: specify and use a RconInboundHandler class
            var rconInboundHandler = new RconInboundHandler(tcsRconResponse, tcsResponse);

            // send reverse connection request instead of normal message
            await SendTcpAsync(rconInboundHandler, tcsRconResponse, rconMessage, channelCreator, connectTimeoutMillis,
                               connectTimeoutMillis, peerConnection);
        }
示例#16
0
        /// <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);
        }
示例#17
0
        private ITcpClientChannel SendTcpPeerConnection(PeerConnection peerConnection, IChannelHandler handler, ChannelCreator channelCreator,
                                                        TaskCompletionSource <Message.Message> tcsResponse)
        {
            // if the channel gets closed, the future should get notified
            var channel = peerConnection.Channel;

            // channel creator can be null if we don't need to create any channels
            if (channelCreator != null)
            {
                // TODO this doesn't do anything yet
                channelCreator.SetupCloseListener(channel, tcsResponse);
            }

            // we need to replace the handler if this comes from the peer that created a peer connection,
            // otherwise we need to add a handler
            AddOrReplace(channel.Pipeline, "dispatcher", "handler", handler);
            // TODO uncommented Java stuff needed?
            return(channel as ITcpClientChannel); // TODO this will fail if its a server channel!!!
        }
示例#18
0
        private TaskCompletionSource<Message.Message> Send(Message.Message message, IConnectionConfiguration configuration,
            ChannelCreator channelCreator)
        {
            var tcsResponse = new TaskCompletionSource<Message.Message>(message);
            tcsResponse.Task.ContinueWith(taskResponse =>
            {
                if (!taskResponse.IsFaulted)
                {
                    var response = taskResponse.Result;
                    if (response != null)
                    {
                        var neighborSet = response.NeighborsSet(0);
                        if (neighborSet != null)
                        {
                            foreach (var neighbor in neighborSet.Neighbors)
                            {
                                lock (PeerBean.PeerStatusListeners)
                                {
                                    foreach (var listener in PeerBean.PeerStatusListeners)
                                    {
                                        listener.PeerFound(neighbor, response.Sender, null);
                                    }
                                }
                            }
                        }
                    }
                }
            });

            var requestHandler = new RequestHandler(tcsResponse, PeerBean, ConnectionBean, configuration);

            if (!configuration.IsForceTcp)
            {
                requestHandler.SendUdpAsync(channelCreator);
            }
            else
            {
                requestHandler.SendTcpAsync(channelCreator);
            }
            // .NET-specific: Return TCS instead of Task. It's actually the same TCS that is provided with
            // the RequestHandler c'tor
            return tcsResponse;
        }
示例#19
0
 /// <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;
 }
示例#20
0
        /// <summary>
        /// Sends a message via UDP.
        /// </summary>
        /// <param name="handler">The handler to deal with the response message.</param>
        /// <param name="tcsResponse">The TCS for the response message. (FutureResponse equivalent.)</param>
        /// <param name="message">The message to send.</param>
        /// <param name="channelCreator">The channel creator for the UDP channel.</param>
        /// <param name="idleUdpSeconds">The idle time of a message until fail.</param>
        /// <param name="broadcast">True, if the message is to be sent via layer 2 broadcast.</param>
        /// <returns>The response message or null, if it is fire-and-forget or a failure occurred.</returns>
        public async Task SendUdpAsync(IInboundHandler handler, TaskCompletionSource<Message.Message> tcsResponse, Message.Message message, ChannelCreator channelCreator, int idleUdpSeconds, bool broadcast)
        {
            // no need to continue if already finished
            if (tcsResponse.Task.IsCompleted)
            {
                return;
            }
            RemovePeerIfFailed(tcsResponse, message);

            bool isFireAndForget = handler == null;

            // relay options
            if (message.Sender.IsRelayed)
            {
                message.SetPeerSocketAddresses(message.Sender.PeerSocketAddresses);

                IList<PeerSocketAddress> relayAddresses = new List<PeerSocketAddress>(message.Recipient.PeerSocketAddresses);
                Logger.Debug("Send neighbor request to random relay peer {0}.", relayAddresses);
                if (relayAddresses.Count > 0)
                {
                    var relayAddress = relayAddresses[_random.NextInt(relayAddresses.Count)];
                    message.SetRecipientRelay(message.Recipient
                        .ChangePeerSocketAddress(relayAddress)
                        .ChangeIsRelayed(true));
                }
                else
                {
                    const string msg = "Peer is relayed, but no relay is given.";
                    Logger.Error(msg);
                    tcsResponse.SetException(new TaskFailedException(msg));
                    return;
                }
            }

            // check for invalid UDP connection to unreachable peers
            if (message.Recipient.IsRelayed && message.Command != Rpc.Rpc.Commands.Neighbor.GetNr()
                && message.Command != Rpc.Rpc.Commands.Ping.GetNr())
            {
                string msg =
                    String.Format(
                        "Tried to send a UDP message to unreachable peers. Only TCP messages can be sent to unreachable peers: {0}.",
                        message);
                Logger.Warn(msg);
                tcsResponse.SetException(new TaskFailedException(msg));
                return;
            }

            // pipeline handler setup
            TimeoutFactory timeoutFactory = CreateTimeoutHandler(tcsResponse, idleUdpSeconds, isFireAndForget);
            var handlers = new Dictionary<string, IChannelHandler>();
            if (!isFireAndForget)
            {
                handlers.Add("timeout0", timeoutFactory.CreateIdleStateHandlerTomP2P());
                handlers.Add("timeout1", timeoutFactory.CreateTimeHandler());
            }
            handlers.Add("decoder", new TomP2PSinglePacketUdp(ChannelClientConfiguration.SignatureFactory));
            handlers.Add("encoder", new TomP2POutbound(false, ChannelClientConfiguration.SignatureFactory));
            if (!isFireAndForget)
            {
                handlers.Add("handler", handler);
            }
            
            // create UDP channel
            MyUdpClient udpClient = null;
            try
            {
                udpClient = channelCreator.CreateUdp(broadcast, handlers);
            }
            catch (Exception ex)
            {
                string msg = "Channel creation failed. " + ex;
                Logger.Debug(msg);
                tcsResponse.SetException(ex);
                // may have been closed by the other side
                // or it may have been canceled from this side
            }

            // "afterConnect"
            // check if channel could be created (due to shutdown)
            if (udpClient == null)
            {
                const string msg = "Could not create a UDP socket. (Due to shutdown.)";
                Logger.Warn(msg);
                tcsResponse.SetException(new TaskFailedException(msg));
                return;
            }
            Logger.Debug("About to connect to {0} with channel {1}, ff = {2}.", message.Recipient, udpClient, isFireAndForget);

            // send request message
            // processes client-side outbound pipeline
            // (await for possible exception re-throw, does not block)
            await udpClient.SendMessageAsync(message);

            // if not fire-and-forget, receive response
            if (isFireAndForget)
            {
                Logger.Debug("Fire and forget message {0} sent. Close channel {1} now.", message, udpClient);
                tcsResponse.SetResult(null); // set FF result
            }
            else
            {
                // receive response message
                // processes client-side inbound pipeline
                await udpClient.ReceiveMessageAsync();
            }
            udpClient.Close();
        }
示例#21
0
 /// <summary>
 /// Sends a TCP message and expects a response.
 /// </summary>
 /// <param name="channelCreator">The channel creator will create a TCP connection.</param>
 /// <param name="peerConnection"></param>
 /// <returns>The future task that was added in the constructor.</returns>
 public Task<Message.Message> SendTcpAsync(ChannelCreator channelCreator, PeerConnection peerConnection)
 {
     var sendTask = ConnectionBean.Sender.SendTcpAsync(this, _tcsResponse, _message, channelCreator, IdleTcpSeconds,
         ConnectionTimeoutTcpMillis, peerConnection);
     return ExecuteAsync(sendTask);
 }
示例#22
0
        /// <summary>
        /// Sends a message via UDP.
        /// </summary>
        /// <param name="handler">The handler to deal with the response message.</param>
        /// <param name="tcsResponse">The TCS for the response message. (FutureResponse equivalent.)</param>
        /// <param name="message">The message to send.</param>
        /// <param name="channelCreator">The channel creator for the UDP channel.</param>
        /// <param name="idleUdpSeconds">The idle time of a message until fail.</param>
        /// <param name="broadcast">True, if the message is to be sent via layer 2 broadcast.</param>
        /// <returns>The response message or null, if it is fire-and-forget or a failure occurred.</returns>
        public async Task SendUdpAsync(IInboundHandler handler, TaskCompletionSource <Message.Message> tcsResponse, Message.Message message, ChannelCreator channelCreator, int idleUdpSeconds, bool broadcast)
        {
            // no need to continue if already finished
            if (tcsResponse.Task.IsCompleted)
            {
                return;
            }
            RemovePeerIfFailed(tcsResponse, message);

            bool isFireAndForget = handler == null;

            // relay options
            if (message.Sender.IsRelayed)
            {
                message.SetPeerSocketAddresses(message.Sender.PeerSocketAddresses);

                IList <PeerSocketAddress> relayAddresses = new List <PeerSocketAddress>(message.Recipient.PeerSocketAddresses);
                Logger.Debug("Send neighbor request to random relay peer {0}.", relayAddresses);
                if (relayAddresses.Count > 0)
                {
                    var relayAddress = relayAddresses[_random.NextInt(relayAddresses.Count)];
                    message.SetRecipientRelay(message.Recipient
                                              .ChangePeerSocketAddress(relayAddress)
                                              .ChangeIsRelayed(true));
                }
                else
                {
                    const string msg = "Peer is relayed, but no relay is given.";
                    Logger.Error(msg);
                    tcsResponse.SetException(new TaskFailedException(msg));
                    return;
                }
            }

            // check for invalid UDP connection to unreachable peers
            if (message.Recipient.IsRelayed && message.Command != Rpc.Rpc.Commands.Neighbor.GetNr() &&
                message.Command != Rpc.Rpc.Commands.Ping.GetNr())
            {
                string msg =
                    String.Format(
                        "Tried to send a UDP message to unreachable peers. Only TCP messages can be sent to unreachable peers: {0}.",
                        message);
                Logger.Warn(msg);
                tcsResponse.SetException(new TaskFailedException(msg));
                return;
            }

            // pipeline handler setup
            TimeoutFactory timeoutFactory = CreateTimeoutHandler(tcsResponse, idleUdpSeconds, isFireAndForget);
            var            handlers       = new Dictionary <string, IChannelHandler>();

            if (!isFireAndForget)
            {
                handlers.Add("timeout0", timeoutFactory.CreateIdleStateHandlerTomP2P());
                handlers.Add("timeout1", timeoutFactory.CreateTimeHandler());
            }
            handlers.Add("decoder", new TomP2PSinglePacketUdp(ChannelClientConfiguration.SignatureFactory));
            handlers.Add("encoder", new TomP2POutbound(false, ChannelClientConfiguration.SignatureFactory));
            if (!isFireAndForget)
            {
                handlers.Add("handler", handler);
            }

            // create UDP channel
            MyUdpClient udpClient = null;

            try
            {
                udpClient = channelCreator.CreateUdp(broadcast, handlers);
            }
            catch (Exception ex)
            {
                string msg = "Channel creation failed. " + ex;
                Logger.Debug(msg);
                tcsResponse.SetException(ex);
                // may have been closed by the other side
                // or it may have been canceled from this side
            }

            // "afterConnect"
            // check if channel could be created (due to shutdown)
            if (udpClient == null)
            {
                const string msg = "Could not create a UDP socket. (Due to shutdown.)";
                Logger.Warn(msg);
                tcsResponse.SetException(new TaskFailedException(msg));
                return;
            }
            Logger.Debug("About to connect to {0} with channel {1}, ff = {2}.", message.Recipient, udpClient, isFireAndForget);

            // send request message
            // processes client-side outbound pipeline
            // (await for possible exception re-throw, does not block)
            await udpClient.SendMessageAsync(message);

            // if not fire-and-forget, receive response
            if (isFireAndForget)
            {
                Logger.Debug("Fire and forget message {0} sent. Close channel {1} now.", message, udpClient);
                tcsResponse.SetResult(null); // set FF result
            }
            else
            {
                // receive response message
                // processes client-side inbound pipeline
                await udpClient.ReceiveMessageAsync();
            }
            udpClient.Close();
        }
示例#23
0
        /// <summary>
        /// Creates a channel creator for permanent TCP connections.
        /// </summary>
        /// <param name="permitsPermanentTcp">The number of long-lived TCP connections.</param>
        /// <returns>The future channel creator.</returns>
        public Task <ChannelCreator> CreatePermanentAsync(int permitsPermanentTcp)
        {
            if (permitsPermanentTcp > _maxPermitsPermanentTcp)
            {
                throw new ArgumentException(String.Format("Cannot acquire more permantent TCP connections ({0}) than maximally allowed ({1}).", permitsPermanentTcp, _maxPermitsPermanentTcp));
            }
            var tcsChannelCreator = new TaskCompletionSource <ChannelCreator>();

            _readWriteLock.EnterReadLock();
            try
            {
                if (_shutdown)
                {
                    tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                    return(tcsChannelCreator.Task);
                }

                var tcsChannelCreationDone = new TaskCompletionSource <object>();
                tcsChannelCreationDone.Task.ContinueWith(delegate
                {
                    // release the permits in all cases
                    // otherwise, we may see inconsistencies
                    _semaphorePermanentTcp.Release(permitsPermanentTcp);
                });

                // instead of Executor.execute(new WaitReservationPermanent())
                _singleThreadTaskFactory.StartNew(delegate
                {
                    // Creates a reservation that returns a channel creator in a
                    // task, once we have the semaphore.
                    // Tries to reserve a channel creator. If too many channels are already
                    // created, wait until channels are closed.
                    ChannelCreator channelCreator;
                    _readWriteLock.EnterReadLock();
                    try
                    {
                        if (_shutdown)
                        {
                            tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                        }

                        try
                        {
                            _semaphorePermanentTcp.Acquire(permitsPermanentTcp);
                        }
                        catch (Exception ex)
                        {
                            tcsChannelCreator.SetException(ex);
                            return;
                        }

                        channelCreator = new ChannelCreator(tcsChannelCreationDone, 0, permitsPermanentTcp, _channelClientConfiguration);
                        AddToSet(channelCreator);
                    }
                    finally
                    {
                        _readWriteLock.ExitReadLock();
                    }
                    tcsChannelCreator.SetResult(channelCreator);
                });

                return(tcsChannelCreator.Task);
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
示例#24
0
        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);
                }
            });
        }
示例#25
0
 public TcsRouting Quit(RoutingBuilder routingBuilder, ChannelCreator cc)
 {
     ICollection<PeerAddress> startPeers = _peerBean.PeerMap.ClosePeers(routingBuilder.LocationKey,
         routingBuilder.Parallel * 2);
     return Routing(startPeers, routingBuilder, Message.Message.MessageType.Request4, cc);
 }
示例#26
0
 /// <summary>
 /// Broadscasts a UDP message (layer 2) and expects a response.
 /// </summary>
 /// <param name="channelCreator">The channel creator will create a UDP connection.</param>
 /// <returns>The future task that was added in the constructor.</returns>
 public Task<Message.Message> SendBroadcastUdpAsync(ChannelCreator channelCreator)
 {
     var sendTask = ConnectionBean.Sender.SendUdpAsync(this, _tcsResponse, _message, channelCreator, IdleUdpSeconds, true);
     return ExecuteAsync(sendTask);
 }
示例#27
0
 /// <summary>
 /// Sends a UDP message and expects a response.
 /// </summary>
 /// <param name="channelCreator">The channel creator will create a UDP connection.</param>
 /// <returns>The future task that was added in the constructor.</returns>
 public Task<Message.Message> SendUdpAsync(ChannelCreator channelCreator)
 {
     // so far, everything is sync -> invoke async / new thread
     var sendTask = ConnectionBean.Sender.SendUdpAsync(this, _tcsResponse, _message, channelCreator, IdleUdpSeconds, false);
     return ExecuteAsync(sendTask);
 }
示例#28
0
        private async Task ConnectAndSendAsync(IInboundHandler handler, TaskCompletionSource <Message.Message> tcsResponse, ChannelCreator channelCreator, int connectTimeoutMillis, PeerConnection peerConnection, TimeoutFactory timeoutHandler, Message.Message message)
        {
            var recipient = message.Recipient.CreateSocketTcp();
            var channel   = SendTcpCreateChannel(recipient, channelCreator, peerConnection, handler, timeoutHandler,
                                                 connectTimeoutMillis);

            await AfterConnectAsync(tcsResponse, message, channel, handler == null);
        }
示例#29
0
        /// <summary>
        /// Creates a channel creator for permanent TCP connections.
        /// </summary>
        /// <param name="permitsPermanentTcp">The number of long-lived TCP connections.</param>
        /// <returns>The future channel creator.</returns>
        public Task<ChannelCreator> CreatePermanentAsync(int permitsPermanentTcp)
        {
            if (permitsPermanentTcp > _maxPermitsPermanentTcp)
            {
                throw new ArgumentException(String.Format("Cannot acquire more permantent TCP connections ({0}) than maximally allowed ({1}).", permitsPermanentTcp, _maxPermitsPermanentTcp));
            }
            var tcsChannelCreator = new TaskCompletionSource<ChannelCreator>();
            _readWriteLock.EnterReadLock();
            try
            {
                if (_shutdown)
                {
                    tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                    return tcsChannelCreator.Task;
                }

                var tcsChannelCreationDone = new TaskCompletionSource<object>();
                tcsChannelCreationDone.Task.ContinueWith(delegate
                {
                    // release the permits in all cases
                    // otherwise, we may see inconsistencies
                    _semaphorePermanentTcp.Release(permitsPermanentTcp);
                });

                // instead of Executor.execute(new WaitReservationPermanent())
                _singleThreadTaskFactory.StartNew(delegate
                {
                    // Creates a reservation that returns a channel creator in a
                    // task, once we have the semaphore.
                    // Tries to reserve a channel creator. If too many channels are already
                    // created, wait until channels are closed.
                    ChannelCreator channelCreator;
                    _readWriteLock.EnterReadLock();
                    try
                    {
                        if (_shutdown)
                        {
                            tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                        }

                        try
                        {
                            _semaphorePermanentTcp.Acquire(permitsPermanentTcp);
                        }
                        catch (Exception ex)
                        {
                            tcsChannelCreator.SetException(ex);
                            return;
                        }

                        channelCreator = new ChannelCreator(tcsChannelCreationDone, 0, permitsPermanentTcp, _channelClientConfiguration);
                        AddToSet(channelCreator);
                    }
                    finally
                    {
                        _readWriteLock.ExitReadLock();
                    }
                    tcsChannelCreator.SetResult(channelCreator);
                });

                return tcsChannelCreator.Task;
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
示例#30
0
        /// <summary>
        /// Sends a UDP message and doesn't expect a response.
        /// </summary>
        /// <param name="channelCreator">The channel creator will create a UDP connection.</param>
        /// <returns>The future task that was added in the constructor.</returns>
        public Task <Message.Message> FireAndForgetUdpAsync(ChannelCreator channelCreator)
        {
            var sendTask = ConnectionBean.Sender.SendUdpAsync(null, _tcsResponse, _message, channelCreator, 0, false);

            return(ExecuteAsync(sendTask));
        }
示例#31
0
        /// <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;
            }
        }
示例#32
0
 /// <summary>
 /// Sends a UDP message and doesn't expect a response.
 /// </summary>
 /// <param name="channelCreator">The channel creator will create a UDP connection.</param>
 /// <returns>The future task that was added in the constructor.</returns>
 public Task<Message.Message> FireAndForgetUdpAsync(ChannelCreator channelCreator)
 {
     var sendTask = ConnectionBean.Sender.SendUdpAsync(null, _tcsResponse, _message, channelCreator, 0, false);
     return ExecuteAsync(sendTask);
 }
示例#33
0
        /// <summary>
        /// Sends a message via TCP.
        /// </summary>
        /// <param name="handler">The handler to deal with the response message.</param>
        /// <param name="tcsResponse">The TCS for the response message. (FutureResponse equivalent.)</param>
        /// <param name="message">The message to send.</param>
        /// <param name="channelCreator">The channel creator for the TCP channel.</param>
        /// <param name="idleTcpSeconds">The idle time until message fail.</param>
        /// <param name="connectTimeoutMillis">The idle time for the connection setup.</param>
        /// <param name="peerConnection"></param>
        /// <returns></returns>
        public async Task SendTcpAsync(IInboundHandler handler, TaskCompletionSource<Message.Message> tcsResponse,
            Message.Message message, ChannelCreator channelCreator, int idleTcpSeconds, int connectTimeoutMillis,
            PeerConnection peerConnection)
        {
            // no need to continue if already finished
            if (tcsResponse.Task.IsCompleted)
            {
                return;
            }
            RemovePeerIfFailed(tcsResponse, message);

            bool isFireAndForget = handler == null;

            // we need to set the neighbors if we use relays
            if (message.Sender.IsRelayed && message.Sender.PeerSocketAddresses.Count != 0)
            {
                message.SetPeerSocketAddresses(message.Sender.PeerSocketAddresses);
            }
            if (peerConnection != null && peerConnection.Channel != null && peerConnection.Channel.IsOpen)
            {
                var channel = SendTcpPeerConnection(peerConnection, handler, channelCreator, tcsResponse);
                await AfterConnectAsync(tcsResponse, message, channel, isFireAndForget);
            }
            else if (channelCreator != null)
            {
                var timeoutHandler = CreateTimeoutHandler(tcsResponse, idleTcpSeconds, handler == null);
                // check relay
                if (message.Recipient.IsRelayed)
                {
                    // check if reverse connection is possible
                    if (!message.Sender.IsRelayed)
                    {
                        await HandleRconAsync(handler, tcsResponse, message, channelCreator, connectTimeoutMillis, peerConnection,
                            timeoutHandler);
                    }
                    else
                    {
                        await HandleRelayAsync(handler, tcsResponse, message, channelCreator, idleTcpSeconds, connectTimeoutMillis,
                            peerConnection, timeoutHandler);
                    }
                }
                // normal connection
                else
                {
                    await ConnectAndSendAsync(handler, tcsResponse, channelCreator, connectTimeoutMillis, peerConnection,
                        timeoutHandler, message);
                }
            }
        }
示例#34
0
        /// <summary>
        /// Creates a channel creator for short-lived connections.
        /// Always call <see cref="ChannelCreator.ShutdownAsync"/> to release all resources.
        /// (This needs to be done in any case, whether it succeeds or fails.)
        /// </summary>
        /// <param name="permitsUdp">The number of short-lived UDP connections.</param>
        /// <param name="permitsTcp">The number of short-lived TCP connections.</param>
        /// <returns>The future channel creator.</returns>
        public Task <ChannelCreator> CreateAsync(int permitsUdp, int permitsTcp)
        {
            if (permitsUdp > _maxPermitsUdp)
            {
                throw new ArgumentException(String.Format("Cannot acquire more UDP connections ({0}) than maximally allowed ({1}).", permitsUdp, _maxPermitsUdp));
            }
            if (permitsTcp > _maxPermitsTcp)
            {
                throw new ArgumentException(String.Format("Cannot acquire more TCP connections ({0}) than maximally allowed ({1}).", permitsTcp, _maxPermitsTcp));
            }
            var tcsChannelCreator = new TaskCompletionSource <ChannelCreator>();

            _readWriteLock.EnterReadLock();
            try
            {
                if (_shutdown)
                {
                    tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                    return(tcsChannelCreator.Task);
                }

                var tcsChannelCreationDone = new TaskCompletionSource <object>();
                tcsChannelCreationDone.Task.ContinueWith(delegate
                {
                    // release the permits in all cases
                    // otherwise, we may see inconsistencies
                    //Console.WriteLine("Reservation ({0}): A CC shut down. Releasing {1} UDP, {2} TCP permits.", RuntimeHelpers.GetHashCode(this), permitsUdp, permitsTcp);
                    _semaphoreUdp.Release2(permitsUdp);
                    _semaphoreTcp.Release2(permitsTcp);
                });

                // instead of Executor.execute(new WaitReservation())
                _singleThreadTaskFactory.StartNew(delegate
                {
                    //Console.WriteLine("Reservation ({0}): Executing async reservation...", RuntimeHelpers.GetHashCode(this));
                    // Creates a reservation that returns a channel creator in a
                    // task, once we have the semaphore.
                    // Tries to reserve a channel creator. If too many channels are already
                    // created, wait until channels are closed.

                    ChannelCreator channelCreator;
                    _readWriteLock.EnterReadLock();
                    try
                    {
                        if (_shutdown)
                        {
                            tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                            return;
                        }
                        try
                        {
                            //Console.Write("[{0}] Reservation ({1}): Acquiring {2} UDP permits.", Thread.CurrentThread.ManagedThreadId, RuntimeHelpers.GetHashCode(this), permitsUdp);
                            _semaphoreUdp.Acquire(permitsUdp);
                            //Console.Write("({0}) --> granted\n", RuntimeHelpers.GetHashCode(this));
                        }
                        catch (Exception ex)
                        {
                            tcsChannelCreator.SetException(ex);
                            return;
                        }
                        try
                        {
                            _semaphoreTcp.Acquire(permitsTcp);
                        }
                        catch (Exception ex)
                        {
                            _semaphoreUdp.Release(permitsUdp);
                            tcsChannelCreator.SetException(ex);
                            return;
                        }

                        channelCreator = new ChannelCreator(tcsChannelCreationDone, permitsUdp, permitsTcp,
                                                            _channelClientConfiguration);
                        AddToSet(channelCreator);
                    }
                    finally
                    {
                        _readWriteLock.ExitReadLock();
                    }
                    tcsChannelCreator.SetResult(channelCreator);
                });

                return(tcsChannelCreator.Task);
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
示例#35
0
 /// <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);
 }
示例#36
0
        /// <summary>
        /// This method initiates the reverse connection setup.
        /// It creates a new message and sends it via relay to the unreachable peer
        /// which then connects to this peer again. After the connect message from the
        /// unreachable peer, this peer will send the original message and its content
        /// directly.
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="tcsResponse"></param>
        /// <param name="message"></param>
        /// <param name="channelCreator"></param>
        /// <param name="connectTimeoutMillis"></param>
        /// <param name="peerConnection"></param>
        /// <param name="timeoutHandler"></param>
        private async Task HandleRconAsync(IInboundHandler handler, TaskCompletionSource<Message.Message> tcsResponse,
            Message.Message message, ChannelCreator channelCreator, int connectTimeoutMillis,
            PeerConnection peerConnection, TimeoutFactory timeoutHandler)
        {
            message.SetKeepAlive(true);

            Logger.Debug("Initiate reverse connection setup to peer with address {0}.", message.Recipient);
            var rconMessage = CreateRconMessage(message);

            // TODO works?
            // cache the original message until the connection is established
            _cachedRequests.AddOrUpdate(message.MessageId, tcsResponse, (i, source) => tcsResponse);

            // wait for response (whether the reverse connection setup was successful)
            var tcsRconResponse = new TaskCompletionSource<Message.Message>(rconMessage);

            // .NET-specific: specify and use a RconInboundHandler class
            var rconInboundHandler = new RconInboundHandler(tcsRconResponse, tcsResponse);

            // send reverse connection request instead of normal message
            await SendTcpAsync(rconInboundHandler, tcsRconResponse, rconMessage, channelCreator, connectTimeoutMillis,
                connectTimeoutMillis, peerConnection);
        }
示例#37
0
        /// <summary>
        /// // TODO document
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="tcsResponse"></param>
        /// <param name="message"></param>
        /// <param name="channelCreator"></param>
        /// <param name="idleTcpSeconds"></param>
        /// <param name="connectTimeoutMillis"></param>
        /// <param name="peerConnection"></param>
        /// <param name="timeoutHandler"></param>
        private async Task HandleRelayAsync(IInboundHandler handler, TaskCompletionSource<Message.Message> tcsResponse,
            Message.Message message, ChannelCreator channelCreator, int idleTcpSeconds, int connectTimeoutMillis,
            PeerConnection peerConnection, TimeoutFactory timeoutHandler)
        {
            var taskPingDone = PingFirst(message.Recipient.PeerSocketAddresses);
            await taskPingDone;
            if (!taskPingDone.IsFaulted)
            {
                var recipient = PeerSocketAddress.CreateSocketTcp(taskPingDone.Result);
                var channel = SendTcpCreateChannel(recipient, channelCreator, peerConnection, handler,
                    timeoutHandler, connectTimeoutMillis);
                await AfterConnectAsync(tcsResponse, message, channel, handler == null);

                // TODO add this before AfterConnect?
                var taskResponse = tcsResponse.Task;
                await taskResponse;
                if (taskResponse.IsFaulted)
                {
                    if (taskResponse.Result != null &&
                        taskResponse.Result.Type != Message.Message.MessageType.User1)
                    {
                        // "clearInactivePeerSocketAddress"
                        var tmp = new List<PeerSocketAddress>();
                        foreach (var psa in message.Recipient.PeerSocketAddresses)
                        {
                            if (psa != null)
                            {
                                if (!psa.Equals(taskPingDone.Result))
                                {
                                    tmp.Add(psa);
                                }
                            }
                        }
                        message.SetPeerSocketAddresses(tmp);

                        await SendTcpAsync(handler, tcsResponse, message, channelCreator, idleTcpSeconds,
                            connectTimeoutMillis, peerConnection);
                    }
                }
            }
            else
            {
                // .NET-specific:
                tcsResponse.SetException(new TaskFailedException("No relay could be contacted. <-> " + taskPingDone.Exception));
            }
        }
示例#38
0
        private ITcpClientChannel SendTcpPeerConnection(PeerConnection peerConnection, IChannelHandler handler, ChannelCreator channelCreator,
            TaskCompletionSource<Message.Message> tcsResponse)
        {
            // if the channel gets closed, the future should get notified
            var channel = peerConnection.Channel;

            // channel creator can be null if we don't need to create any channels
            if (channelCreator != null)
            {
                // TODO this doesn't do anything yet
                channelCreator.SetupCloseListener(channel, tcsResponse);
            }

            // we need to replace the handler if this comes from the peer that created a peer connection,
            // otherwise we need to add a handler
            AddOrReplace(channel.Pipeline, "dispatcher", "handler", handler);
            // TODO uncommented Java stuff needed?
            return channel as ITcpClientChannel; // TODO this will fail if its a server channel!!!
        }
示例#39
0
        /// <summary>
        /// Needs 3 connections. Cleans up channel creator, which means they will be released.
        /// </summary>
        /// <param name="tcsDiscover"></param>
        /// <param name="peerAddress"></param>
        /// <param name="cc"></param>
        /// <param name="configuration"></param>
        private void Discover(TcsDiscover tcsDiscover, PeerAddress peerAddress, ChannelCreator cc,
            IConnectionConfiguration configuration)
        {
            _peer.PingRpc.AddPeerReachableListener(new DiscoverPeerReachableListener(tcsDiscover));

            var taskResponseTcp = _peer.PingRpc.PingTcpDiscoverAsync(peerAddress, cc, configuration, SenderAddress);
            taskResponseTcp.ContinueWith(taskResponse =>
            {
                var serverAddress = _peer.PeerBean.ServerPeerAddress;
                if (!taskResponse.IsFaulted)
                {
                    var tmp = taskResponseTcp.Result.NeighborsSet(0).Neighbors;
                    tcsDiscover.SetReporter(taskResponseTcp.Result.Sender);
                    if (tmp.Count == 1)
                    {
                        var seenAs = tmp.First();
                        Logger.Info("This peer is seen as {0} by peer {1}. This peer sees itself as {2}.", seenAs, peerAddress, _peer.PeerAddress.InetAddress);
                        if (!_peer.PeerAddress.InetAddress.Equals(seenAs.InetAddress))
                        {
                            // check if we have this interface on that we can listen to
                            var bindings = new Bindings().AddAddress(seenAs.InetAddress);
                            var status = DiscoverNetworks.DiscoverInterfaces(bindings);
                            Logger.Info("2nd interface discovery: {0}.", status);
                            if (bindings.FoundAddresses.Count > 0
                                && bindings.FoundAddresses.Contains(seenAs.InetAddress))
                            {
                                serverAddress = serverAddress.ChangeAddress(seenAs.InetAddress);
                                _peer.PeerBean.SetServerPeerAddress(serverAddress);
                                Logger.Info("This peer had the wrong interface. Changed it to {0}.", serverAddress);
                            }
                            else
                            {
                                // now we know our internal IP, where we receive packets
                                var ports =
                                    _peer.ConnectionBean.ChannelServer.ChannelServerConfiguration.PortsForwarding;
                                if (ports.IsManualPort)
                                {
                                    serverAddress = serverAddress.ChangePorts(ports.TcpPort, ports.UdpPort);
                                    serverAddress = serverAddress.ChangeAddress(seenAs.InetAddress);
                                    _peer.PeerBean.SetServerPeerAddress(serverAddress);
                                    Logger.Info("This peer had manual ports. Changed it to {0}.", serverAddress);
                                }
                                else
                                {
                                    // we need to find a relay, because there is a NAT in the way
                                    tcsDiscover.SetExternalHost(
                                        "We are most likely behind a NAT. Try to UPNP, NAT-PMP or relay " + peerAddress, taskResponseTcp.Result.Recipient.InetAddress, seenAs.InetAddress);
                                    return;
                                }
                            }
                        }
                        // else -> we announce exactly how the other peer sees us
                        var taskResponse1 = _peer.PingRpc.PingTcpProbeAsync(peerAddress, cc, configuration);
                        taskResponse1.ContinueWith(tr1 =>
                        {
                            if (tr1.IsFaulted)
                            {
                                tcsDiscover.SetException(new TaskFailedException("TcsDiscover (2): We need at least the TCP connection.", tr1));
                            }
                        });
                        
                        var taskResponse2 = _peer.PingRpc.PingUdpProbeAsync(peerAddress, cc, configuration);
                        taskResponse2.ContinueWith(tr2 =>
                        {
                            if (tr2.IsFaulted)
                            {
                                Logger.Warn("TcsDiscover (2): UDP failed connection.");
                            }
                        });

                        // from here we probe, set the timeout here
                        tcsDiscover.Timeout(serverAddress, _peer.ConnectionBean.Timer, DiscoverTimeoutSec);
                        return;
                    }
                    tcsDiscover.SetException(new TaskFailedException(String.Format("Peer {0} did not report our IP address.", peerAddress)));
                }
                else
                {
                    tcsDiscover.SetException(new TaskFailedException("TcsDiscover (1): We need at least the TCP connection.", taskResponse));
                }
            });
        }
示例#40
0
 private async Task ConnectAndSendAsync(IInboundHandler handler, TaskCompletionSource<Message.Message> tcsResponse, ChannelCreator channelCreator, int connectTimeoutMillis, PeerConnection peerConnection, TimeoutFactory timeoutHandler, Message.Message message)
 {
     var recipient = message.Recipient.CreateSocketTcp();
     var channel = SendTcpCreateChannel(recipient, channelCreator, peerConnection, handler, timeoutHandler,
         connectTimeoutMillis);
     await AfterConnectAsync(tcsResponse, message, channel, handler == null);
 }
示例#41
0
        /// <summary>
        /// Creates a channel creator for short-lived connections.
        /// Always call <see cref="ChannelCreator.ShutdownAsync"/> to release all resources.
        /// (This needs to be done in any case, whether it succeeds or fails.)
        /// </summary>
        /// <param name="permitsUdp">The number of short-lived UDP connections.</param>
        /// <param name="permitsTcp">The number of short-lived TCP connections.</param>
        /// <returns>The future channel creator.</returns>
        public Task<ChannelCreator> CreateAsync(int permitsUdp, int permitsTcp)
        {
            if (permitsUdp > _maxPermitsUdp)
            {
                throw new ArgumentException(String.Format("Cannot acquire more UDP connections ({0}) than maximally allowed ({1}).", permitsUdp, _maxPermitsUdp));
            }
            if (permitsTcp > _maxPermitsTcp)
            {
                throw new ArgumentException(String.Format("Cannot acquire more TCP connections ({0}) than maximally allowed ({1}).", permitsTcp, _maxPermitsTcp));
            }
            var tcsChannelCreator = new TaskCompletionSource<ChannelCreator>();
            _readWriteLock.EnterReadLock();
            try
            {
                if (_shutdown)
                {
                    tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                    return tcsChannelCreator.Task;
                }

                var tcsChannelCreationDone = new TaskCompletionSource<object>();
                tcsChannelCreationDone.Task.ContinueWith(delegate
                {
                    // release the permits in all cases
                    // otherwise, we may see inconsistencies
                    //Console.WriteLine("Reservation ({0}): A CC shut down. Releasing {1} UDP, {2} TCP permits.", RuntimeHelpers.GetHashCode(this), permitsUdp, permitsTcp);
                    _semaphoreUdp.Release2(permitsUdp);
                    _semaphoreTcp.Release2(permitsTcp);
                });

                // instead of Executor.execute(new WaitReservation())
                _singleThreadTaskFactory.StartNew(delegate
                {
                    //Console.WriteLine("Reservation ({0}): Executing async reservation...", RuntimeHelpers.GetHashCode(this));
                    // Creates a reservation that returns a channel creator in a
                    // task, once we have the semaphore.
                    // Tries to reserve a channel creator. If too many channels are already
                    // created, wait until channels are closed.

                    ChannelCreator channelCreator;
                    _readWriteLock.EnterReadLock();
                    try
                    {
                        if (_shutdown)
                        {
                            tcsChannelCreator.SetException(new TaskFailedException("Shutting down."));
                            return;
                        }
                        try
                        {
                            //Console.Write("[{0}] Reservation ({1}): Acquiring {2} UDP permits.", Thread.CurrentThread.ManagedThreadId, RuntimeHelpers.GetHashCode(this), permitsUdp);
                            _semaphoreUdp.Acquire(permitsUdp);
                            //Console.Write("({0}) --> granted\n", RuntimeHelpers.GetHashCode(this));
                        }
                        catch (Exception ex)
                        {
                            tcsChannelCreator.SetException(ex);
                            return;
                        }
                        try
                        {
                            _semaphoreTcp.Acquire(permitsTcp);
                        }
                        catch (Exception ex)
                        {
                            _semaphoreUdp.Release(permitsUdp);
                            tcsChannelCreator.SetException(ex);
                            return;
                        }

                        channelCreator = new ChannelCreator(tcsChannelCreationDone, permitsUdp, permitsTcp,
                            _channelClientConfiguration);
                        AddToSet(channelCreator);
                    }
                    finally
                    {
                        _readWriteLock.ExitReadLock();
                    }
                    tcsChannelCreator.SetResult(channelCreator);
                });

                return tcsChannelCreator.Task;
            }
            finally
            {
                _readWriteLock.ExitReadLock();
            }
        }
示例#42
0
        private ITcpClientChannel SendTcpCreateChannel(IPEndPoint recipient, ChannelCreator channelCreator,
            PeerConnection peerConnection, IChannelHandler handler, TimeoutFactory timeoutHandler, int connectTimeoutMillis)
        {
            // create pipeline
            var handlers = new Dictionary<string, IChannelHandler>();
            if (timeoutHandler != null)
            {
                handlers.Add("timeout0", timeoutHandler.CreateIdleStateHandlerTomP2P());
                handlers.Add("timeout1", timeoutHandler.CreateTimeHandler());
            }
            handlers.Add("decoder", new TomP2PCumulationTcp(ChannelClientConfiguration.SignatureFactory));
            handlers.Add("encoder", new TomP2POutbound(false, ChannelClientConfiguration.SignatureFactory));
            if (peerConnection != null)
            {
                // we expect responses on this connection
                handlers.Add("dispatcher", _dispatcher);
            }
            if (timeoutHandler != null)
            {
                handlers.Add("handler", handler);
            }
            HeartBeat heartBeat = null;
            if (peerConnection != null)
            {
                heartBeat = new HeartBeat(peerConnection.HeartBeatMillis, PingBuilderFactory);
                handlers.Add("heartbeat", heartBeat);
            }

            var channel = channelCreator.CreateTcp(recipient, connectTimeoutMillis, handlers);

            if (peerConnection != null && channel != null)
            {
                peerConnection.SetChannel(channel);
                heartBeat.SetPeerConnection(peerConnection);
            }
            return channel;
        }
示例#43
0
 /// <summary>
 /// Adds a channel creator to the set and also adds it to the shutdown listener.
 /// </summary>
 /// <param name="channelCreator"></param>
 private void AddToSet(ChannelCreator channelCreator)
 {
     channelCreator.ShutdownTask.ContinueWith(delegate
     {
         _readWriteLock.EnterReadLock();
         try
         {
             if (_shutdown)
             {
                 return;
             }
             //Console.WriteLine("Removing channel creator from set.");
             _channelCreators.Remove(channelCreator);
         }
         finally
         {
             _readWriteLock.ExitReadLock();
         }
     });
     _channelCreators.Add(channelCreator);
 }
示例#44
0
        /// <summary>
        /// Broadscasts a UDP message (layer 2) and expects a response.
        /// </summary>
        /// <param name="channelCreator">The channel creator will create a UDP connection.</param>
        /// <returns>The future task that was added in the constructor.</returns>
        public Task <Message.Message> SendBroadcastUdpAsync(ChannelCreator channelCreator)
        {
            var sendTask = ConnectionBean.Sender.SendUdpAsync(this, _tcsResponse, _message, channelCreator, IdleUdpSeconds, true);

            return(ExecuteAsync(sendTask));
        }