Exemplo n.º 1
0
 public GcMessage(GcPeer sender, byte flags)
 {
     Peer       = sender;
     RequestId  = -1;
     ResponseId = -1;
     OpCode     = -1;
     Flags      = flags;
 }
Exemplo n.º 2
0
        public GcPeer(int peerId, GcPeer concretePeer)
        {
            _writer         = new NetWriter();
            _relayedPeerIds = new Dictionary <GcConnection, int>();
            PeerId          = peerId;

            IsVirtual     = true;
            _concretePeer = concretePeer;
        }
Exemplo n.º 3
0
        private void OnConnectionReceived(PeerConnection connection)
        {
            var peerId = Interlocked.Increment(ref _peerIdGenerator);
            var peer   = new GcPeer(peerId, connection);

            _peersByConnectionId.TryAdd(connection.ConnectionId, peer);
            _peers.TryAdd(peerId, peer);

            PeerJoined?.Invoke(peer);
        }
Exemplo n.º 4
0
        public static GcMessage ParseMessage(GcPeer peer, byte[] data)
        {
            var reader = new NetReader(data);

            var flags  = reader.ReadByte();
            var opCode = reader.ReadInt16();

            // Read peer id if it's provided
            if ((flags & MessageFlags.PaddedPeerId) > 0)
            {
                // Read padded peer id
                reader.ReadInt32();
            }

            var msg = new GcMessage(peer, flags)
            {
                OpCode = opCode,
                Reader = reader
            };

            if ((flags & MessageFlags.Request) > 0)
            {
                var requestId = reader.ReadInt32();
                msg.RequestId = requestId;
            }

            if ((flags & MessageFlags.Response) > 0)
            {
                var responseId     = reader.ReadInt32();
                var responseStatus = (ResponseStatus)reader.ReadByte();
                msg.ResponseId = responseId;
                msg.Status     = responseStatus;
            }

            return(msg);
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="peerId"></param>
 /// <param name="peer"></param>
 /// <exception cref="NotImplementedException"></exception>
 internal void SaveRelayedPeer(int peerId, GcPeer peer)
 {
     _relayedPeers.TryAdd(peerId, peer);
 }
Exemplo n.º 6
0
        private void OnRawDataReceived(PeerConnection sender, byte[] data)
        {
            // If the message is empty - ignore
            if (data.Length < 0)
            {
                return;
            }

            try
            {
                var flags = data[0];

                if ((flags & MessageFlags.InternalMessage) > 0)
                {
                    HandleInternalMessage(sender, data);
                    return;
                }

                // 1. Get the peer
                GcPeer peer = null;
                if ((flags & MessageFlags.PaddedPeerId) > 0)
                {
                    // There's a peer id within a message, which means that this message
                    // was relayed from somewhere, and we need to use an "indirect" peer
                    var peerId = EndianBitConverter.Little.ToInt32(data, 3);

                    if (peerId <= 0)
                    {
                        // This was just an empty padding, ignore it, use a direct peer
                        _peersByConnectionId.TryGetValue(sender.ConnectionId, out peer);
                    }
                    else
                    {
                        // Get a peer with provided peer id
                        _peers.TryGetValue(peerId, out peer);
                    }
                }
                else
                {
                    _peersByConnectionId.TryGetValue(sender.ConnectionId, out peer);
                }

                // Received a message from connection which has no direct peer object
                if (peer == null)
                {
                    _logger.LogWarning("Received a message from a source which doesn't have a peer");
                    return;
                }

                // 2. Handle relaying of messages
                if (_relayConnections.Count != 0)
                {
                    var          opCode = EndianBitConverter.Little.ToInt16(data, 1);
                    GcConnection connectionToRelay;
                    _relayConnections.TryGetValue(opCode, out connectionToRelay);

                    // If connection to relay for this opcode exists, it means a message
                    // needs to be relayed
                    if (connectionToRelay != null)
                    {
                        // Write relayed peer id into the messages peerId padding
                        var relayedId = peer.GetPeerIdInRelayedServer(connectionToRelay);

                        // Ignore if peer doesn't have an established peer id
                        if (relayedId < 0)
                        {
                            return;
                        }

                        // TODO Do this only if there's a peerId padding, otherwise - reconstruct the whole thing
                        // Add a peer id
                        EndianBitConverter.Little.CopyBytes(relayedId, data, 3);

                        // Pass the data
                        connectionToRelay.Implementation.SendRawData(data);
                        return;
                    }
                }

                // 3. Generate the message object
                var message = GcProtocol.ParseMessage(peer, data);

                HandleMessage(message);
            }
            catch (Exception e)
            {
                _logger.LogError("Exception while handling received data", e);
            }
        }
Exemplo n.º 7
0
        private async Task HandleEstablishPeer(GcMessage message)
        {
            var    peerId          = message.Reader.ReadInt32();
            var    isDirectMessage = peerId < 0;
            GcPeer peer            = null;

            if (isDirectMessage)
            {
                // This is a direct message from client
                // who can't know his peer id
                peerId = message.Peer.PeerId;
                peer   = message.Peer;
            }
            else
            {
                // This is a message that was already relayed at least once
                // We need to create a virtual peer which will be used in this server
                var vPeer = new GcPeer(Interlocked.Increment(ref _peerIdGenerator), message.Peer);

                _peers.TryAdd(vPeer.PeerId, vPeer);
                PeerJoined?.Invoke(vPeer);

                // Add the newly created peer id
                peerId = vPeer.PeerId;
                peer   = vPeer;
            }

            // Send messages to all of the relayed servers to establish a peer in them
            var connections = _relayConnections.Values.Distinct().Where(c => c.IsConnected);

            var allSuccessful = true;

            // Do it "linearly" (one by one) because it's a lot easier to handle
            foreach (var connection in connections)
            {
                var response =
                    await connection.SendRequest((short)InternalOpCodes.EstablishPeer, w => w.Write(peerId));

                if (response.Status != ResponseStatus.Success)
                {
                    _logger.LogWarning("Failed to establish a peer in connection: " + connection);
                    allSuccessful = false;
                    continue;
                }

                var assignedPeerId = response.Reader.ReadInt32();

                // For forwarding messages
                peer.SetPeerIdInRelayedServer(assignedPeerId, connection);

                // For "backwarding" messages
                connection.SaveRelayedPeer(assignedPeerId, peer);
            }

            if (isDirectMessage)
            {
                message.Respond(allSuccessful ? ResponseStatus.Success : ResponseStatus.Failed);
            }
            else
            {
                message.Respond(ResponseStatus.Success, w => w.Write(peerId));
            }
        }