/// <summary> /// Handles an incoming connection request. /// </summary> /// <param name="ep">The source of the request.</param> /// <param name="accept">A function to call to accept the connection request.</param> protected override void HandleConnection(ErebusEndpoint ep, Func <Stream> accept) => htsm.RunSafe(() => { foreach (var h in htsm.RunSafe(() => invitationHandlers.ToArray())) { h(this, new SSMPInvitationReceivedEventArgs(ep.Address, () => { Connected = true; var s = accept(); r = new BinaryReader(s, Encoding.UTF8, true); w = new BinaryWriter(s, Encoding.UTF8, true); return(this); })); if (Connected) { recvTask = recvProcess(); return; } } });
/// <summary> /// Sends a connection request to the given destination on the given port. /// </summary> /// <param name="ep">The destination.</param> /// <returns>A stream for sending and receiving data over the connection, or null if the connection was denied.</returns> protected Stream RequestConnection(ErebusEndpoint ep) { Log.RecordEvent(this, $"Connecting to {ep}...", LogEntrySeverity.Info); ei.SendPacket(ep, new byte[] { 0 }.Concat(localId.ToByteArray()).ToArray()); byte type = 0; byte[] recv = waitRecv12(ei, int.MaxValue, ep.Port, b => { type = b; return(b == 1 || b == 2); }, localId); if (type == 2) { return(null); } remoteId = new Guid(recv); retrieveKeys(ep.Address); Log.RecordEvent(this, $"Connected to {ep} with local GUID {localId} and remote GUID {remoteId}", LogEntrySeverity.Info); Endpoint = ep; return(createStream(ep)); }
/// <summary> /// Sends a packet to the specified destination on the specified port. /// </summary> /// <param name="ep">The destination of the packet.</param> /// <param name="data">The contents of the packet.</param> protected void SendPacket(ErebusEndpoint ep, byte[] data) => ei.SendPacket(ep, data);
static internal void HandlePacket(Packet packet, ErebusInstance instance) { try { if (packet.Data.Length == 0) { Log.RecordEvent(typeof(BCPProtocolBase), $"BCP packet from {packet.Source} is empty.", LogEntrySeverity.Error); return; } switch (packet.Data[0]) { case 0: ErebusEndpoint ep = new ErebusEndpoint(packet.Source, packet.Port); if (packet.Data.Length != 17) { Log.RecordEvent(typeof(BCPProtocolBase), $"BCP connection request packet from {ep} is an invalid size!", LogEntrySeverity.Warning); } BCPProtocolBase p; try { p = ptsm.RunSafe(() => protocols[packet.Port])(instance); p.remoteId = new Guid(packet.Data.Skip(1).ToArray()); } catch (KeyNotFoundException) { Log.RecordEvent(typeof(BCPProtocolBase), $"No protocol is associated with port {packet.Port}!", LogEntrySeverity.Warning); instance.SendPacket(ep, new byte[] { 2 }.Concat(packet.Data.Skip(1)).ToArray()); return; } try { bool accepted = false; p.Endpoint = ep; p.HandleConnection(ep, () => { accepted = true; instance.SendPacket(ep, new byte[] { 1 }.Concat(p.remoteId.ToByteArray()).Concat(p.localId.ToByteArray()).ToArray()); Log.RecordEvent(p, $"Connected to {ep} with local GUID {p.localId} and remote GUID {p.remoteId}", LogEntrySeverity.Info); p.retrieveKeys(packet.Source); return(p.createStream(ep)); }); if (!accepted) { instance.SendPacket(ep, new byte[] { 2 }.Concat(p.remoteId.ToByteArray()).ToArray()); } } catch (Exception e) { Log.RecordEvent(typeof(BCPProtocolBase), $"Error calling connection handler on {p.GetType()}: {e.Message}", LogEntrySeverity.Error); } break; case 3: var i = itsm.RunSafe(() => instanceData[instance]); i.TSM.RunSafe(() => { Guid id = new Guid(packet.Data.Range(1, 16).ToArray()); ulong pos = BitConverter.ToUInt64(packet.Data.Range(17, 8).ToArray(), 0); var data = packet.Data.Skip(25).ToArray(); var cp = i.CurrentPositions[id]; if (pos < cp) { Log.RecordEvent(typeof(BCPProtocolBase), "BCP packet received for known data.", LogEntrySeverity.Warning); } else { var oflow = i.Overflow3[id]; var newOflow = new byte?[Math.Max((int)((ulong)data.Length + pos - cp), oflow.Length)]; Array.Copy(oflow, newOflow, oflow.Length); Array.Copy(data.Cast <byte?>().ToArray(), 0, newOflow, (int)(pos - cp), data.Length); i.Overflow3[id] = newOflow; refresh3(i, id, packet.Port); } }); break; default: var itm = itsm.RunSafe(() => instanceData[instance]); itm.TSM.RunSafe(() => { var data = packet.Data.Skip(17).ToArray(); foreach (var c in (from d in itm.Callbacks12 where d.Item1 == packet.Port && d.Item3 == new Guid(packet.Data.Range(1, 16).ToArray()) && d.Item4(packet.Data[0]) select d).ToArray()) { itm.Callbacks12.Remove(c); c.Item5(data.Range(0, Math.Min(data.Length, c.Item2)).ToArray()); if (c.Item2 <= data.Length) { data = data.Skip(c.Item2).ToArray(); } else { data = new byte[0]; } if (data.Length == 0) { break; } } if (data.Length != 0) { itm.Overflow12.AddLast(new Tuple <ushort, byte, Guid, byte[]>(packet.Port, packet.Data[0], new Guid(packet.Data.Range(1, 16).ToArray()), data)); } }); break; } } catch (Exception e) { Log.RecordEvent(typeof(BCPProtocolBase), $"Exception in BCP main packet handler: {e.Message}", LogEntrySeverity.Error); } }
/// <summary> /// Handles an incoming connection request. /// </summary> /// <param name="ep">The source of the request.</param> /// <param name="accept">A function to call to accept the request and retrieve a stream for communication.</param> abstract protected void HandleConnection(ErebusEndpoint ep, Func <Stream> accept);
Stream createStream(ErebusEndpoint ep) => new EncryptionNegotiator().Negotiate(new BCPStream(data => stsm.RunSafe(() => { ei.SendPacket(ep, new byte[] { 3 }.Concat(remoteId.ToByteArray()).Concat(BitConverter.GetBytes(sendPos)).Concat(data).ToArray()); sendPos += (ulong)data.Length; }), l => waitRecv3(ei, l, ep.Port, localId), myKey, otherKey));