예제 #1
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);
                }
            }
        }
예제 #2
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));
            }
        }
예제 #3
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!!!
        }
예제 #4
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);
        }
예제 #5
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);
        }
예제 #6
0
 public HeartBeat SetPeerConnection(PeerConnection peerConnection)
 {
     _peerConnection = peerConnection;
     return(this);
 }
예제 #7
0
        public override void Read(ChannelHandlerContext ctx, object msg)
        {
            // server-side:
            // message comes (over network) from sender
            // -> correct DispatchHandler handles response

            // Java uses a SimpleChannelInboundHandler that only expects Message objects
            var requestMessage = msg as Message.Message;

            if (requestMessage == null)
            {
                return;
            }

            Logger.Debug("Received request message {0} from channel {1}.", requestMessage, ctx.Channel);
            if (requestMessage.Version != _p2PId)
            {
                Logger.Error("Wrong version. We are looking for {0}, but we got {1}. Received: {2}.", _p2PId, requestMessage.Version, requestMessage);
                ctx.Close(); // TODO used?
                lock (_peerBeanMaster.PeerStatusListeners)
                {
                    foreach (IPeerStatusListener listener in _peerBeanMaster.PeerStatusListeners)
                    {
                        listener.PeerFailed(requestMessage.Sender,
                                            new PeerException(PeerException.AbortCauseEnum.PeerError, "Wrong P2P version."));
                    }
                }
                return;
            }
            if (!requestMessage.IsRequest())
            {
                Logger.Debug("Handing request message to the next handler. {0}", requestMessage);
                ctx.FireRead(msg);
                return;
            }

            IResponder      responder = new DirectResponder(this, _peerBeanMaster, ctx, requestMessage);
            DispatchHandler myHandler = AssociatedHandler(requestMessage);

            if (myHandler != null)
            {
                bool isUdp   = ctx.Channel.IsUdp;
                bool isRelay = requestMessage.Sender.IsRelayed;
                if (!isRelay && requestMessage.PeerSocketAddresses.Count != 0)
                {
                    PeerAddress sender =
                        requestMessage.Sender.ChangePeerSocketAddresses(requestMessage.PeerSocketAddresses);
                    requestMessage.SetSender(sender);
                }
                Logger.Debug("About to respond to request message {0}.", requestMessage);

                // handle the request message
                PeerConnection peerConnection = null;
                if (!isUdp)
                {
                    var tcpChannel = ctx.Channel as ITcpChannel;
                    peerConnection = new PeerConnection(requestMessage.Sender, tcpChannel, _heartBeatMillis);
                }
                myHandler.ForwardMessage(requestMessage, peerConnection, responder);
            }
            else
            {
                // do better error handling
                // if a handler is not present at all, print a warning
                if (_ioHandlers.Count == 0)
                {
                    Logger.Debug("No handler found for request message {0}. This peer has probably been shut down.", requestMessage);
                }
                else
                {
                    var knownCommands = KnownCommands();
                    if (knownCommands.Contains(Convert.ToInt32(requestMessage.Command)))
                    {
                        var sb = new StringBuilder();
                        foreach (int cmd in knownCommands)
                        {
                            sb.Append((Rpc.Rpc.Commands)cmd + "; ");
                        }
                        Logger.Warn("No handler found for request message {0}. Is the RPC command {1} registered? Found registered: {2}.", requestMessage, (Rpc.Rpc.Commands)requestMessage.Command, sb);
                    }
                    else
                    {
                        Logger.Debug("No handler found for request message {0}. This peer has probably been partially shut down.", requestMessage);
                    }
                }

                // return response that states that no handler was found
                var responseMessage = DispatchHandler.CreateResponseMessage(requestMessage,
                                                                            Message.Message.MessageType.UnknownId, _peerBeanMaster.ServerPeerAddress);

                Respond(ctx, responseMessage);
            }
        }
예제 #8
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);
        }