private void SendPacketEnvelope(SocketState connection, PacketEnvelope envelope) { byte[] sendBuffer = Packetizer.AssembleMessagePacket(envelope, connection.UseCompression, false, null, null); Stats.BytesSent += (UInt64)sendBuffer.Length; connection.Socket.Send(sendBuffer, sendBuffer.Length, SocketFlags.None); }
private void SendPacketEnvelope(SocketState connection, PacketEnvelope envelope, string encryptionKey, string salt) { byte[] sendBuffer = Packetizer.AssembleMessagePacket(envelope, connection.UseCompression, true, encryptionKey, salt); Stats.BytesSent += (UInt64)sendBuffer.Length; connection.Socket.Send(sendBuffer, sendBuffer.Length, SocketFlags.None); }
void ProcessReceivedData(SocketState connection, byte[] buffer, int bufferSize) { string sharedSecretString = connection.Peer.IsEncryptionNegotationComplete ? connection.Peer.KeyNegotiator.SharedSecretString : null; string commonSalt = null; if (connection.Peer.IsIncomming && connection.Peer.IsEncryptionNegotationComplete) { commonSalt = _route.BindingPreSharedKey; } else if (connection.Peer.IsOutgoing && connection.Peer.IsEncryptionNegotationComplete) { commonSalt = _route.EndpointPreSharedKey; } if (_route.TrafficType == TrafficType.Http) { HttpHeaderType httpHeaderType = HttpHeaderType.None; string httpHeader = null; string httpRequestVerb = string.Empty; if (connection.HttpHeaderBuilder != string.Empty) { //This is a continuation of a previously received fragmented header. httpHeader = (connection.HttpHeaderBuilder ?? string.Empty) + Encoding.UTF8.GetString(buffer); httpHeaderType = HttpUtility.IsHttpHeader(httpHeader, out httpRequestVerb); } else { httpHeaderType = HttpUtility.IsHttpHeader(buffer, bufferSize, out httpRequestVerb); if (httpHeaderType != HttpHeaderType.None) { httpHeader = Encoding.UTF8.GetString(buffer); } } if (httpHeaderType != HttpHeaderType.None) { string lineBreak = ""; int endOfHeaderPos = HttpUtility.GetHttpHeaderEnd(httpHeader, out lineBreak); if (endOfHeaderPos < 0) { throw new NotSupportedException(); //Not sure what to do yet. } if (endOfHeaderPos > bufferSize) { throw new InvalidOperationException(); //Not sure what to do yet. } httpHeader = httpHeader.Substring(0, endOfHeaderPos).Trim(new char[] { '\r', '\n', ' ', '\0' }); httpHeader = ApplyHttpHeaderRules(httpHeader, httpHeaderType, httpRequestVerb, lineBreak); httpHeader += lineBreak + lineBreak; //Terminate the header. int contentLength = bufferSize - (endOfHeaderPos - connection.HttpHeaderBuilder.Length); connection.HttpHeaderBuilder = string.Empty; byte[] fullReponse = new byte[httpHeader.Length + contentLength]; Buffer.BlockCopy(System.Text.Encoding.UTF8.GetBytes(httpHeader), 0, fullReponse, 0, httpHeader.Length); if (contentLength > 0) { Buffer.BlockCopy(buffer, endOfHeaderPos, fullReponse, httpHeader.Length, contentLength); } if (connection.Peer.UsePackets) { //Console.WriteLine("--Send:{0}, Packet: {1}", route.Name, Encoding.UTF8.GetString(fullReponse.Take(fullReponse.Length).ToArray())); byte[] sendBuffer = Packetizer.AssembleMessagePacket(fullReponse, fullReponse.Length, connection.Peer.UseCompression, connection.Peer.UseEncryption, sharedSecretString, commonSalt); Stats.BytesSent += (UInt64)sendBuffer.Length; connection.Peer.Socket.Send(sendBuffer, sendBuffer.Length, SocketFlags.None); WaitForData(connection); } else { //Console.WriteLine("--Send:{0}, Raw: {1}", route.Name, Encoding.UTF8.GetString(fullReponse.Take(fullReponse.Length).ToArray())); Stats.BytesSent += (UInt64)fullReponse.Length; connection.Peer.Socket.Send(fullReponse, fullReponse.Length, SocketFlags.None); } return; } } if (connection.Peer.UsePackets) { //Console.WriteLine("--Send:{0}, Packet: {1}", route.Name, Encoding.UTF8.GetString(buffer.Take(bufferSize).ToArray())); byte[] sendBuffer = Packetizer.AssembleMessagePacket(buffer, bufferSize, connection.Peer.UseCompression, connection.Peer.UseEncryption, sharedSecretString, commonSalt); Stats.BytesSent += (UInt64)sendBuffer.Length; connection.Peer.Socket.Send(sendBuffer, sendBuffer.Length, SocketFlags.None); } else { //Console.WriteLine("--Send:{0}, Raw: {1}", route.Name, Encoding.UTF8.GetString(buffer.Take(bufferSize).ToArray())); Stats.BytesSent += (UInt64)bufferSize; connection.Peer.Socket.Send(buffer, bufferSize, SocketFlags.None); } }
private void OnDataReceived(IAsyncResult asyn) { SocketState connection = null; try { connection = (SocketState)asyn.AsyncState; connection.BytesReceived = connection.Socket.EndReceive(asyn); if (connection.BytesReceived == 0) { CleanupConnection(connection); return; } string sharedSecretString = connection.IsEncryptionNegotationComplete ? connection.KeyNegotiator.SharedSecretString : null; string commonSalt = null; if (connection.IsIncomming && connection.IsEncryptionNegotationComplete) { commonSalt = _route.BindingPreSharedKey; } else if (connection.IsOutgoing && connection.IsEncryptionNegotationComplete) { commonSalt = _route.EndpointPreSharedKey; } if (connection.UsePackets) { //Console.WriteLine("--Recv:{0}, Packet: {1}", route.Name, Encoding.UTF8.GetString(connection.Buffer.Take(connection.BytesReceived).ToArray())); List <PacketEnvelope> envelopes = Packetizer.DissasemblePacketData(this, connection, connection.UseCompression, connection.IsEncryptionNegotationComplete, sharedSecretString, commonSalt); foreach (var envelope in envelopes) { if (envelope.Label == null) { if (connection.IsTunnelNegotationComplete) { //Console.WriteLine("--Recv: {0} {1}", envelope.Payload.Length, Encoding.UTF8.GetString(envelope.Payload.Take(envelope.Payload.Length).ToArray())); ProcessReceivedData(connection, envelope.Payload, envelope.Payload.Length); } else { Stats.DroppedPreNegotiatePacket++; //Console.WriteLine("--Dropped packet, tunnel negotation is not yet complete", route.Name); } } else { ProcessPeerCommand(connection, envelope); } } } else { //Console.WriteLine("--Recv:{0}, Raw: {1}", route.Name, Encoding.UTF8.GetString(connection.Buffer.Take(connection.BytesReceived).ToArray())); //If we are supposed to use encryption, nut its not been initialized then we need to wait before processing the received data. //This is because we do not yet have the information required to decrypt it. //Try a spin lock first, then start sleeping. if (connection.IsTunnelNegotationComplete == false) { WaitForData(connection); int spinCount = _route.SpinLockCount; DateTime?startTime = null; while (connection.IsTunnelNegotationComplete == false) { //TODO: This needs to timeout. if (spinCount == 0) { startTime = DateTime.Now; } else if (startTime != null) { if ((DateTime.Now - ((DateTime)startTime)).TotalMilliseconds > _route.EncryptionInitilizationTimeoutMs) { break; } Thread.Sleep(1); } spinCount--; } } if (connection.IsTunnelNegotationComplete) { ProcessReceivedData(connection, connection.Buffer, connection.BytesReceived); } else { Stats.DroppedPreNegotiateRawData++; Console.WriteLine("--Dropped Raw Data Segment", _route.Name); } } WaitForData(connection); } catch (ObjectDisposedException) { if (connection != null) { CleanupConnection(connection); } return; } catch (SocketException) { if (connection != null) { CleanupConnection(connection); } return; } catch (Exception ex) { Singletons.EventLog.WriteEvent(new EventLogging.EventPayload { Severity = EventLogging.Severity.Error, CustomText = "Failed to process received data.", Exception = ex }); } }
void EstablishPeerConnection(object connectionObject) { SocketState accpetedConnection = (SocketState)connectionObject; SocketState foreignConnection = null; Endpoint foreignConnectionEndpoint = null; string stickeySessionKey = _route.Name + ":" + _route.Endpoints.ConnectionPattern + ":" + ((IPEndPoint)accpetedConnection.Socket.RemoteEndPoint).Address.ToString(); if (_route.UseStickySessions) { lock (_stickySessionCache) { if (_stickySessionCache.Contains(stickeySessionKey)) { var cacheItem = (StickySession)_stickySessionCache[stickeySessionKey]; foreignConnectionEndpoint = (from o in _route.Endpoints.List where o.Address == cacheItem.DestinationAddress && o.Port == cacheItem.DestinationPort select o).FirstOrDefault(); } } } //Attempt to connect to the same address as we did last time. if (foreignConnectionEndpoint != null) { if ((foreignConnection = Connect(foreignConnectionEndpoint.Address, foreignConnectionEndpoint.Port)) != null) { //Success. } } //If not using sticky sessions, of if we failed to connect to the previously successful host - then take the connection pattern into account. if (foreignConnection == null) { if (_route.Endpoints.ConnectionPattern == ConnectionPattern.FailOver) { foreach (var remotePeer in _route.Endpoints.List) { if (remotePeer.Enabled) { if ((foreignConnection = Connect(remotePeer.Address, remotePeer.Port)) != null) { foreignConnectionEndpoint = remotePeer; break; } } } } else if (_route.Endpoints.ConnectionPattern == ConnectionPattern.Balanced) { throw new NotImplementedException(); } else if (_route.Endpoints.ConnectionPattern == ConnectionPattern.RoundRobbin) { if (_lastRoundRobinIndex >= _route.Endpoints.List.Count) { _lastRoundRobinIndex = 0; } int startIndex = _lastRoundRobinIndex++; if (startIndex >= _route.Endpoints.List.Count) { startIndex = 0; } for (int i = startIndex; i < _route.Endpoints.List.Count; i++) { var remotePeer = _route.Endpoints.List[i]; if (remotePeer.Enabled) { if ((foreignConnection = Connect(remotePeer.Address, remotePeer.Port)) != null) { foreignConnectionEndpoint = remotePeer; break; } } } } else { throw new NotImplementedException(); } } if (foreignConnection == null) { CleanupConnection(accpetedConnection); return; } if (_route.UseStickySessions) { lock (_stickySessionCache) { var stickySession = new StickySession() { DestinationAddress = foreignConnectionEndpoint.Address, DestinationPort = foreignConnectionEndpoint.Port }; _stickySessionCache.Add(stickeySessionKey, stickySession, new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0, 0, _route.StickySessionCacheExpiration) }); } } accpetedConnection.Peer = foreignConnection; foreignConnection.Peer = accpetedConnection; lock (_connections) { _connections.Add(accpetedConnection); _connections.Add(foreignConnection); } WaitForData(accpetedConnection); WaitForData(foreignConnection); }
public static List <PacketEnvelope> DissasemblePacketData(Router router, SocketState state, bool compress, bool encrypt, string encryptPacketKey, string keySalt) { List <PacketEnvelope> envelopes = new List <PacketEnvelope>(); try { if (state.PayloadBuilderLength + state.BytesReceived >= state.PayloadBuilder.Length) { Array.Resize(ref state.PayloadBuilder, state.PayloadBuilderLength + state.BytesReceived); } Buffer.BlockCopy(state.Buffer, 0, state.PayloadBuilder, state.PayloadBuilderLength, state.BytesReceived); state.PayloadBuilderLength = state.PayloadBuilderLength + state.BytesReceived; while (state.PayloadBuilderLength > Constants.PayloadHeaderSize) //[PayloadSize] and [CRC16] { Byte[] payloadDelimiterBytes = new Byte[4]; Byte[] payloadSizeBytes = new Byte[4]; Byte[] expectedCrc16Bytes = new Byte[2]; Buffer.BlockCopy(state.PayloadBuilder, 0, payloadDelimiterBytes, 0, payloadDelimiterBytes.Length); Buffer.BlockCopy(state.PayloadBuilder, 4, payloadSizeBytes, 0, payloadSizeBytes.Length); Buffer.BlockCopy(state.PayloadBuilder, 8, expectedCrc16Bytes, 0, expectedCrc16Bytes.Length); int payloadDelimiter = BitConverter.ToInt32(payloadDelimiterBytes, 0); int grossPayloadSize = BitConverter.ToInt32(payloadSizeBytes, 0); UInt16 expectedCrc16 = BitConverter.ToUInt16(expectedCrc16Bytes, 0); if (payloadDelimiter != Constants.PayloadDelimiter) { SkipPacket(ref state); //throw new Exception("Malformed payload packet, invalid delimiter."); router.Stats.PacketMalformedCount++; continue; } if (grossPayloadSize < Constants.DefaultMinMsgSize || grossPayloadSize > Constants.DefaultMaxMsgSize) { SkipPacket(ref state); //throw new Exception("Malformed payload packet, invalid length."); router.Stats.PacketSizeExceededCount++; continue; } if (state.PayloadBuilderLength < grossPayloadSize) { //We have data in the buffer, but it's not enough to make up // the entire message (fragmented packet) so we will break and wait on more data. router.Stats.PacketFragmentCount++; break; } UInt16 actualCrc16 = Crc16.ComputeChecksum(state.PayloadBuilder, Constants.PayloadHeaderSize, grossPayloadSize - Constants.PayloadHeaderSize); if (actualCrc16 != expectedCrc16) { SkipPacket(ref state); //throw new Exception("Malformed payload packet, invalid CRC."); router.Stats.PacketCrcFailureCount++; continue; } int netPayloadSize = grossPayloadSize - Constants.PayloadHeaderSize; byte[] payloadBytes = new byte[netPayloadSize]; Buffer.BlockCopy(state.PayloadBuilder, Constants.PayloadHeaderSize, payloadBytes, 0, netPayloadSize); if (encrypt) { payloadBytes = Decrypt(encryptPacketKey, keySalt, payloadBytes); } if (compress) { payloadBytes = Unzip(payloadBytes); } envelopes.Add((PacketEnvelope)Serialization.ByteArrayToObject(payloadBytes)); //Zero out the consumed portion of the payload buffer - more for fun than anything else. Array.Clear(state.PayloadBuilder, 0, grossPayloadSize); Buffer.BlockCopy(state.PayloadBuilder, grossPayloadSize, state.PayloadBuilder, 0, state.PayloadBuilderLength - grossPayloadSize); state.PayloadBuilderLength -= grossPayloadSize; } } catch (Exception ex) { //TODO: allow this to be logged. } return(envelopes); }