/// <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(); } } }
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); } }
/// <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); }
public override void Read(ChannelHandlerContext ctx, object msg) { _lastReadTime.Set(Convenient.CurrentTimeMillis()); ctx.FireRead(msg); }
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); } }