/// <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); } } }
/// <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)); } }
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!!! }
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); }
/// <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); }
public HeartBeat SetPeerConnection(PeerConnection peerConnection) { _peerConnection = peerConnection; return(this); }
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); } }
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); }