/// <summary>
        /// .NET-specific decoding handler for incoming UDP messages.
        /// </summary>
        public override void Read(ChannelHandlerContext ctx, object msg)
        {
            var dgram = msg as DatagramPacket;
            if (dgram == null)
            {
                ctx.FireRead(msg);
                return;
            }

            var buf = dgram.Content;
            var sender = dgram.Sender;
            var recipient = dgram.Recipient;

            try
            {
                var decoder = new Decoder(_signatureFactory);
                bool finished = decoder.Decode(ctx, buf, recipient, sender);
                if (finished)
                {
                    // prepare finish
                    ctx.FireRead(decoder.PrepareFinish());
                }
                else
                {
                    Logger.Warn("Did not get the complete packet!");
                }
            }
            catch (Exception ex)
            {
                Logger.Error("Error in UDP decoding.", ex);
                throw;
            }
        }
        private void Decoding(ChannelHandlerContext ctx, IPEndPoint sender, IPEndPoint receiver)
        {
            bool finished = true;
            bool moreData = true;
            while (finished && moreData)
            {
                finished = _decoder.Decode(ctx, _cumulation, receiver, sender);
                if (finished)
                {
                    _lastId = _decoder.Message.MessageId;
                    moreData = _cumulation.ReadableBytes > 0;
                    ctx.FireRead(_decoder.PrepareFinish());
                }
                else
                {
                    if (_decoder.Message == null)
                    {
                        // Wait for more data. This may happen if we don't get the first
                        // 58 bytes, which is the size of the header.
                        return;
                    }

                    if (_lastId == _decoder.Message.MessageId)
                    {
                        // This ID was the same as the last and the last message already
                        // finished the parsing. So this message is finished as well, although
                        // it may send only partial content.
                        finished = true;
                        moreData = _cumulation.ReadableBytes > 0;
                        ctx.FireRead(_decoder.PrepareFinish());
                    }
                    else if (_decoder.Message.IsStreaming())
                    {
                        ctx.FireRead(_decoder.Message);
                    }
                    // arriving here, the next handler must not be called since another
                    // current architecture -> skip rest of handlers
                    // TCP packet needs to be cumulated
                    ctx.SkipRestRead();
                }
            }
        }
Esempio n. 3
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);
            }
        }
Esempio n. 4
0
 /// <summary>
 /// Responds within a session. Keeps the connection open if told to do so.
 /// Connection is only kept alive for TCP content.
 /// </summary>
 /// <param name="ctx">The channel context.</param>
 /// <param name="responseMessage">The response message to send.</param>
 internal void Respond(ChannelHandlerContext ctx, Message.Message responseMessage)
 {
     // TODO if/else can be tied together
     if (ctx.Channel is IUdpChannel)
     {
         // Check, if channel is still open. If not, then do not send anything
         // because this will cause an exception that will be logged.
         var channel = ctx.Channel as IUdpChannel;
         if (!channel.IsOpen)
         {
             Logger.Debug("Channel UDP is not open. Do not reply {0}.", responseMessage);
             return;
         }
         Logger.Debug("Response UDP message {0}.", responseMessage);
     }
     else if (ctx.Channel is ITcpChannel)
     {
         // Check, if channel is still open. If not, then do not send anything
         // because this will cause an exception that will be logged.
         var channel = ctx.Channel as ITcpChannel;
         if (!channel.IsOpen)
         {
             Logger.Debug("Channel TCP is not open. Do not reply {0}.", responseMessage);
             return;
         }
         Logger.Debug("Response TCP message {0} to {1}.", responseMessage, "TODO"); // TODO find way to log TCP remoteEndpoint
     }
     ctx.FireRead(responseMessage);
 }
Esempio n. 5
0
 public override void Read(ChannelHandlerContext ctx, object msg)
 {
     _lastReadTime.Set(Convenient.CurrentTimeMillis());
     ctx.FireRead(msg);
 }
Esempio n. 6
0
        public override void Read(ChannelHandlerContext ctx, object msg)
        {
            // client-side:
            // Here, the result for the awaitable task can be set.
            // If it is not a fire-and-forget message, the "result" of the TCS
            // must be set here. (If FF, then it is set in Sender.)

            // Java uses a SimpleChannelInboundHandler that only expects Message objects
            var responseMessage = msg as Message.Message;
            if (responseMessage == null)
            {
                return;
            }

            var recvMessageId = new MessageId(responseMessage);

            // error handling
            if (responseMessage.Type == Message.Message.MessageType.UnknownId)
            {
                string msg2 =
                    "Message was not delivered successfully. Unknown ID (peer may be offline or unknown RPC handler): " +
                    _message;
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }
            if (responseMessage.Type == Message.Message.MessageType.Exception)
            {
                string msg2 = "Message caused an exception on the other side. Handle as PeerAbort: " + _message;
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }
            if (responseMessage.IsRequest())
            {
                ctx.FireRead(responseMessage);
                return;
            }
            if (!_sendMessageId.Equals(recvMessageId))
            {
                string msg2 =
                    String.Format(
                        "Response message [{0}] sent to the node is not the same as we expect. We sent request message [{1}].",
                        responseMessage, _message);
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }
            // We need to exclude RCON messages from the sanity check because we
            // use this RequestHandler for sending a Type.REQUEST_1,
            // RPC.Commands.RCON message on top of it. Therefore the response
            // type will never be the same Type as the one the user initially
            // used (e.g. DIRECT_DATA).
            if (responseMessage.Command != Rpc.Rpc.Commands.Rcon.GetNr()
                     && _message.Recipient.IsRelayed != responseMessage.Sender.IsRelayed)
            {
                string msg2 =
                    String.Format(
                        "Response message [{0}] sent has a different relay flag than we sent with request message [{1}]. Recipient ({2}) / Sender ({3}).",
                        responseMessage, _message, _message.Recipient.IsRelayed, responseMessage.Sender.IsRelayed);
                ExceptionCaught(ctx, new PeerException(PeerException.AbortCauseEnum.PeerAbort, msg2));
                return;
            }

            // we got a good answer, let's mark the sender as alive
            if (responseMessage.IsOk() || responseMessage.IsNotOk())
            {
                lock (PeerBean.PeerStatusListeners)
                {
                    if (responseMessage.Sender.IsRelayed && responseMessage.PeerSocketAddresses.Count != 0)
                    {
                        // use the response message as we have up-to-date content for the relays
                        PeerAddress remotePeer =
                            responseMessage.Sender.ChangePeerSocketAddresses(responseMessage.PeerSocketAddresses);
                        responseMessage.SetSender(remotePeer);
                    }
                    foreach (IPeerStatusListener listener in PeerBean.PeerStatusListeners)
                    {
                        listener.PeerFound(responseMessage.Sender, null, null);
                    }
                }
            }

            // call this for streaming support
            if (!responseMessage.IsDone)
            {
                Logger.Debug("Good message is streaming. {0}", responseMessage);
                return;
            }

            if (!_message.IsKeepAlive())
            {
                Logger.Debug("Good message {0}. Close channel {1}.", responseMessage, ctx.Channel);

                // .NET-specific:
                // set the result now, but trigger the notify when the channel is closed
                _tcsResponse.ResponseLater(responseMessage, ctx);

                // in Java, the channel creator adds a listener that sets the 
                // future response result when the channel is closed
                ctx.Close(); // TODO needed?
            }
            else
            {
                Logger.Debug("Good message {0}. Leave channel {1} open.", responseMessage, ctx.Channel);
                _tcsResponse.SetResult(responseMessage);
            }
        }