/// <summary>
        /// Decodes a message object.
        /// The format looks as follows: 28 bit P2P version, 4 bit message type, 32 bit message ID, 8 bit message command,
        /// 160 bit senderSocket ID, 16 bit senderSocket TCP port, 16 bit senderSocket UDP port, 160 bit recipientSocket ID, 32 bit content types, 8 bit options.
        /// In total, the header is of size 58 bytes.
        /// </summary>
        /// <param name="buffer">The buffer to decode from.</param>
        /// <param name="recipientSocket">The recipientSocket of the message.</param>
        /// <param name="senderSocket">The senderSocket of the packet, which has been set in the socket class.</param> // TODO check if true
        /// <returns>The partial message where only the header fields are set.</returns>
        public static Message DecodeHeader(AlternativeCompositeByteBuf buffer, IPEndPoint recipientSocket, IPEndPoint senderSocket)
        {
            Logger.Debug("Decode message. Recipient: {0}, Sender: {1}", recipientSocket, senderSocket);

            var message = new Message();

            int versionAndType = buffer.ReadInt(); // 4
            message.SetVersion(versionAndType >> 4);
            message.SetType((Message.MessageType)(versionAndType & Utils.Utils.Mask0F)); // TODO does this work? (2x)
            message.SetMessageId(buffer.ReadInt()); // 8
            message.SetCommand(buffer.ReadByte()); // 9 // TODO check conversion with Java version
            var senderId = ReadId(buffer); // 29
            int tcpPort = buffer.ReadUShort(); // 31 // TODO check if should be read as short (same as encode)
            int udpPort = buffer.ReadUShort(); // 33
            var recipientId = ReadId(buffer); // 53
            int contentTypes = buffer.ReadInt(); // 57
            int options = buffer.ReadUByte(); // 58 // TODO check if should be read as unsigned/signed

            message.SetRecipient(new PeerAddress(recipientId, recipientSocket));
            message.HasContent(contentTypes != 0);
            message.SetContentType(DecodeContentTypes(contentTypes, message));
            message.SetOptions(options & Utils.Utils.Mask0F);

            // set the address as we see it, important for port forwarding identification
            int senderOptions = options >> 4;
            var pa = new PeerAddress(senderId, senderSocket.Address, tcpPort, udpPort, senderOptions);

            message.SetSender(pa);
            message.SetSenderSocket(senderSocket);
            message.SetRecipientSocket(recipientSocket);

            return message;
        }
        /// <summary>
        /// Encodes a message object.
        /// The format looks as follows: 28 bit P2P version, 4 bit message type, 32 bit message ID, 8 bit message command,
        /// 160 bit senderSocket ID, 16 bit senderSocket TCP port, 16 bit senderSocket UDP port, 160 bit recipientSocket ID, 32 bit content types, 8 bit options.
        /// In total, the header is of size 58 bytes.
        /// </summary>
        /// <param name="buffer">The buffer to encode to.</param>
        /// <param name="message">The message with the header that will be encoded.</param>
        public static void EncodeHeader(AlternativeCompositeByteBuf buffer, Message message)
        {
            // TODO add log statemet, also in Java version
            int versionAndType = message.Version << 4 | ((int)message.Type & Utils.Utils.Mask0F); // TODO check if ordinal works

            buffer.WriteInt(versionAndType); // 4
            buffer.WriteInt(message.MessageId); // 8
            buffer.WriteByte(message.Command); // 9
            buffer.WriteBytes(message.Sender.PeerId.ToByteArray()); // 29
            buffer.WriteShort((short) message.Sender.TcpPort); // 31 
            buffer.WriteShort((short) message.Sender.UdpPort); // 33
            buffer.WriteBytes(message.Recipient.PeerId.ToByteArray()); // 53
            buffer.WriteInt(EncodeContentTypes(message.ContentTypes)); // 57
            buffer.WriteByte((sbyte) (message.Sender.Options << 4 | message.Options)); // 58 // TODO check if works
        }
Exemple #3
0
        public static Message CreateDummyMessage(Number160 idSender, String inetSender, int tcpPortSendor,
            int udpPortSender, Number160 idRecipient, String inetRecipient, int tcpPortRecipient,
            int udpPortRecipient, sbyte command, Message.MessageType type, bool firewallUdp, bool firewallTcp)
        {
            var message = new Message();

            PeerAddress n1 = CreateAddress(idSender, inetSender, tcpPortSendor, udpPortSender, firewallUdp, firewallTcp);
            message.SetSender(n1);
            //
            PeerAddress n2 = CreateAddress(idRecipient, inetRecipient, tcpPortRecipient, udpPortRecipient, firewallUdp, firewallTcp);
            message.SetRecipient(n2);
            message.SetType(type);
            message.SetCommand(command);
            return message;
        }
Exemple #4
0
 public override void HandleResponse(Message.Message requestMessage, PeerConnection peerConnection, bool sign, IResponder responder)
 {
     if (!(requestMessage.Type == Message.Message.MessageType.RequestFf1
         && requestMessage.Command == Rpc.Commands.Broadcast.GetNr()))
     {
         throw new ArgumentException("Message content is wrong for this handler.");   
     }
     Logger.Debug("Received BROADCAST message: {0}.", requestMessage);
     BroadcastHandler.Receive(requestMessage);
     if (requestMessage.IsUdp)
     {
         responder.ResponseFireAndForget();
     }
     else
     {
         responder.Response(CreateResponseMessage(requestMessage, Message.Message.MessageType.Ok));    
     }
 }
Exemple #5
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);
        }
Exemple #6
0
 private void RemovePeerIfFailed(TaskCompletionSource<Message.Message> tcs, Message.Message message)
 {
     // execute the following delegate only if TCS task failed
     tcs.Task.ContinueWith(delegate(Task task)
     {
         if (message.Recipient.IsRelayed)
         {
             // TODO: Java, make the relay go away if failed
         }
         else
         {
             lock (_peerStatusListeners)
             {
                 foreach (var listener in _peerStatusListeners)
                 {
                     listener.PeerFailed(message.Recipient, new PeerException(tcs));
                 }
             }
         }
     }, TaskContinuationOptions.OnlyOnFaulted);
 }
Exemple #7
0
 private async Task AfterConnectAsync(TaskCompletionSource<Message.Message> tcsResponse, Message.Message message,
     IClientChannel channel, bool isFireAndForget)
 {
     // TODO use for UDP connections, too
     // TODO find clean-mechanism to show the channel-creation fails (UDP uses try/catch)
     // check if channel could be created (due to shutdown)
     if (channel == null)
     {
         string msg = String.Format("Could not create a {0} socket. (Due to shutdown.)", message.IsUdp ? "UDP" : "TCP");
         Logger.Warn(msg);
         tcsResponse.SetException(new TaskFailedException(msg));
         return;
     }
     Logger.Debug("About to connect to {0} with channel {1}, ff = {2}.", message.Recipient, channel, isFireAndForget);
     
     // sending
     var sendTask = channel.SendMessageAsync(message);
     await AfterSendAsync(sendTask, tcsResponse, isFireAndForget, channel);
 }
Exemple #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);
 }
Exemple #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));
            }
        }
Exemple #10
0
        /// <summary>
        /// This method makes a copy of the original message and prepares it for 
        /// sending it to the relay.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private static Message.Message CreateRconMessage(Message.Message message)
        {
            // get relay address from the unreachable peer
            var relayAddresses = message.Recipient.PeerSocketAddresses.ToArray();
            PeerSocketAddress socketAddress;

            if (relayAddresses.Length > 0)
            {
                // we should be fair and choose one of the relays randomly
                socketAddress = relayAddresses[Utils.Utils.RandomPositiveInt(relayAddresses.Length)];
            }
            else
            {
                throw new ArgumentException("There are no PeerSocketAddresses available for this relayed peer. This should not be possible!");
            }

            // we need to make a copy of the original message
            var rconMessage = new Message.Message();
            rconMessage.SetSender(message.Sender);
            rconMessage.SetVersion(message.Version);
            rconMessage.SetIntValue(message.MessageId);

            // make the message ready to send
            PeerAddress recipient =
                message.Recipient
                    .ChangeAddress(socketAddress.InetAddress)
                    .ChangePorts(socketAddress.TcpPort, socketAddress.UdpPort)
                    .ChangeIsRelayed(false);
            rconMessage.SetRecipient(recipient);
            rconMessage.SetCommand(Rpc.Rpc.Commands.Rcon.GetNr());
            rconMessage.SetType(Message.Message.MessageType.Request1);

            return rconMessage;
        }
Exemple #11
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);
        }
Exemple #12
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;
 }
Exemple #13
0
        public override void HandleResponse(Message.Message requestMessage, PeerConnection peerConnection, bool sign, IResponder responder)
        {
            if (requestMessage.KeyList.Count < 2)
            {
                throw new ArgumentException("At least location and domain keys are needed.");
            }
            if (!(requestMessage.Type == Message.Message.MessageType.Request1
                || requestMessage.Type == Message.Message.MessageType.Request2
                || requestMessage.Type == Message.Message.MessageType.Request3
                || requestMessage.Type == Message.Message.MessageType.Request4)
                && (requestMessage.Command == Rpc.Commands.Neighbor.GetNr()))
            {
                throw new ArgumentException("Message content is wrong for this handler.");
            }

            Number160 locationKey = requestMessage.Key(0);
            Number160 domainKey = requestMessage.Key(1);

            var neighbors = GetNeighbors(locationKey, NeighborSize);
            if (neighbors == null)
            {
                // return empty neighbor set
                var response = CreateResponseMessage(requestMessage, Message.Message.MessageType.NotFound);
                response.SetNeighborSet(new NeighborSet(-1, new Collection<PeerAddress>()));
                responder.Response(response);
                return;
            }

            // create response message and set neighbors
            var responseMessage = CreateResponseMessage(requestMessage, Message.Message.MessageType.Ok);

            Logger.Debug("Found the following neighbors: {0}.", Convenient.ToString(neighbors));
            var neighborSet = new NeighborSet(NeighborLimit, neighbors);
            responseMessage.SetNeighborSet(neighborSet);

            Number160 contentKey = requestMessage.Key(2);
            var keyBloomFilter = requestMessage.BloomFilter(0);
            var contentBloomFilter = requestMessage.BloomFilter(1);
            var keyCollection = requestMessage.KeyCollection(0);

            // it is important to set an integer if a value is present
            bool isDigest = requestMessage.Type != Message.Message.MessageType.Request1;
            if (isDigest)
            {
                if (requestMessage.Type == Message.Message.MessageType.Request2)
                {
                    DigestInfo digestInfo;
                    if (PeerBean.DigestStorage == null)
                    {
                        // no storage to search
                        digestInfo = new DigestInfo();
                    }
                    else if (contentKey != null && locationKey != null && domainKey != null)
                    {
                        var locationAndDomainKey = new Number320(locationKey, domainKey);
                        var from = new Number640(locationAndDomainKey, contentKey, Number160.Zero);
                        var to = new Number640(locationAndDomainKey, contentKey, Number160.MaxValue);
                        digestInfo = PeerBean.DigestStorage.Digest(from, to, -1, true);
                    }
                    else if ((keyBloomFilter != null || contentBloomFilter != null) && locationKey != null && domainKey != null)
                    {
                        var locationAndDomainKey = new Number320(locationKey, domainKey);
                        digestInfo = PeerBean.DigestStorage.Digest(locationAndDomainKey, keyBloomFilter,
                                contentBloomFilter, -1, true, true);
                    }
                    else if (keyCollection != null && keyCollection.Keys.Count == 2)
                    {
                        var enumerator = keyCollection.Keys.GetEnumerator();
                        var from = enumerator.MoveNext() ? enumerator.Current : null; // TODO works correctly?
                        var to = enumerator.MoveNext() ? enumerator.Current : null;

                        digestInfo = PeerBean.DigestStorage.Digest(from, to, -1, true);
                    }
                    else if (locationKey != null && domainKey != null)
                    {
                        var locationAndDomainKey = new Number320(locationKey, domainKey);
                        var from = new Number640(locationAndDomainKey, Number160.Zero, Number160.Zero);
                        var to = new Number640(locationAndDomainKey, Number160.MaxValue, Number160.MaxValue);
                        digestInfo = PeerBean.DigestStorage.Digest(from, to, -1, true);
                    }
                    else
                    {
                        Logger.Warn("Did not search for anything.");
                        digestInfo = new DigestInfo();
                    }
                    responseMessage.SetIntValue(digestInfo.Size);
                    responseMessage.SetKey(digestInfo.KeyDigest);
                    responseMessage.SetKey(digestInfo.ContentDigest);
                }
                else if (requestMessage.Type == Message.Message.MessageType.Request3)
                {
                    DigestInfo digestInfo;
                    if (PeerBean.DigestTracker == null)
                    {
                        // no tracker to search
                        digestInfo = new DigestInfo();
                    }
                    else
                    {
                        digestInfo = PeerBean.DigestTracker.Digest(locationKey, domainKey, contentKey);
                        if (digestInfo.Size == 0)
                        {
                            Logger.Debug("No entry found on peer {0}.", requestMessage.Recipient);
                        }
                    }
                    responseMessage.SetIntValue(digestInfo.Size);
                }
                else if (requestMessage.Type == Message.Message.MessageType.Request4)
                {
                    lock (PeerBean.PeerStatusListeners)
                    {
                        foreach (var listener in PeerBean.PeerStatusListeners)
                        {
                            listener.PeerFailed(requestMessage.Sender,
                                new PeerException(PeerException.AbortCauseEnum.Shutdown, "shutdown"));
                        }
                    }
                }
            }

            responder.Response(responseMessage);
        }
Exemple #14
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;
        }
 /// <summary>
 /// Encodes the 8 content types to an integer (32 bit).
 /// </summary>
 /// <param name="contentTypes">The 8 content types to be encoded.</param>
 /// <returns>The encoded 32 bit integer.</returns>
 public static int EncodeContentTypes(Message.Content[] contentTypes)
 {
     int result = 0;
     for (int i = 0; i < Message.ContentTypeLength/2; i++)
     {
         if (contentTypes[i*2] != Message.Content.Empty) // TODO check port
         {
             result |= ((int) contentTypes[i*2] << (i*8)); // TODO check ordinal
         }
         if (contentTypes[i*2 + 1] != Message.Content.Empty)
         {
             result |= ((int) contentTypes[i*2 + 1] << 4) << (i*8);
         }
     }
     return result;
 }
Exemple #16
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();
        }
Exemple #17
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);
                }
            }
        }
 /// <summary>
 /// Decodes the 8 content types from an integer (32 bit).
 /// </summary>
 /// <param name="contentTypes">The 8 content types to be decoded.</param>
 /// <param name="message">The decoded content types.</param>
 /// <returns></returns>
 public static Message.Content[] DecodeContentTypes(int contentTypes, Message message)
 {
     var result = new Message.Content[Message.ContentTypeLength];
     for (int i = 0; i < Message.ContentTypeLength; i++)
     {
         var content = (Message.Content) (contentTypes & Utils.Utils.Mask0F);
         result[i] = content;
         if (content == Message.Content.PublicKeySignature)
         {
             message.SetHintSign();
         }
         contentTypes >>= 4;
     }
     return result;
 }