public GcMessage(GcPeer sender, byte flags) { Peer = sender; RequestId = -1; ResponseId = -1; OpCode = -1; Flags = flags; }
public GcPeer(int peerId, GcPeer concretePeer) { _writer = new NetWriter(); _relayedPeerIds = new Dictionary <GcConnection, int>(); PeerId = peerId; IsVirtual = true; _concretePeer = concretePeer; }
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); }
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); }
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); } }
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)); } }