public void BufferPool() { BufferPool bp = new BufferPool(10000); int ct = 1000; for (int i = 0; i < ct; i++) { byte[] b = bp.GetBuffer(); Assert.AreEqual(10000, b.Length); bp.ReturnBuffer(b); } Console.WriteLine("{0} allocations for {1} uses of buffer pool.", bp.NumAllocations, ct); }
public ushort SendPacket(byte[] packetData, int length, byte channelID) { if (length > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is too large to send, max packet size is " + config.MaxPacketSize + " bytes"); } ushort sequence = this.sequence++; ushort ack; uint ackBits; receivedPackets.GenerateAckBits(out ack, out ackBits); SentPacketData sentPacketData = sentPackets.Insert(sequence); sentPacketData.time = this.time; sentPacketData.packetBytes = (uint)(config.PacketHeaderSize + length); sentPacketData.acked = false; if (length <= config.FragmentThreshold) { // regular packet byte[] transmitData = BufferPool.GetBuffer(2048); int headerBytes = PacketIO.WritePacketHeader(transmitData, channelID, sequence, ack, ackBits); int transmitBufferLength = length + headerBytes; Buffer.BlockCopy(packetData, 0, transmitData, headerBytes, length); config.TransmitPacketCallback(transmitData, transmitBufferLength); BufferPool.ReturnBuffer(transmitData); } else { // fragmented packet byte[] packetHeader = BufferPool.GetBuffer(Defines.MAX_PACKET_HEADER_BYTES); int packetHeaderBytes = PacketIO.WritePacketHeader(packetHeader, channelID, sequence, ack, ackBits); int numFragments = (length / config.FragmentSize) + ((length % config.FragmentSize) != 0 ? 1 : 0); int fragmentBufferSize = Defines.FRAGMENT_HEADER_BYTES + Defines.MAX_PACKET_HEADER_BYTES + config.FragmentSize; byte[] fragmentPacketData = BufferPool.GetBuffer(2048); int qpos = 0; byte prefixByte = 1; prefixByte |= (byte)((channelID & 0x03) << 6); for (int fragmentID = 0; fragmentID < numFragments; fragmentID++) { using (var writer = ByteArrayReaderWriter.Get(fragmentPacketData)) { writer.Write(prefixByte); writer.Write(sequence); writer.Write((byte)fragmentID); writer.Write((byte)(numFragments - 1)); if (fragmentID == 0) { writer.WriteBuffer(packetHeader, packetHeaderBytes); } int bytesToCopy = config.FragmentSize; if (qpos + bytesToCopy > length) { bytesToCopy = length - qpos; } for (int i = 0; i < bytesToCopy; i++) { writer.Write(packetData[qpos++]); } int fragmentPacketBytes = (int)writer.WritePosition; config.TransmitPacketCallback(fragmentPacketData, fragmentPacketBytes); } } BufferPool.ReturnBuffer(packetHeader); BufferPool.ReturnBuffer(fragmentPacketData); } return(sequence); }
public PageScheduler() { _stream = new ConstantStream <Page>(Config.NAME_FILE_PAGE_SOURCE, new PageDeserializer(), capacity => { return(_pool.GetBuffer(capacity)); }); }
/////////////////////////////////////////////////////////////////////////// /// <summary> /// 构造函数 /// </summary> /// <param name="stream"></param> public luaProtoReader(MemoryStream stream) { _stream = stream; _buff = BufferPool.GetBuffer(); }
public void ReceivePacket(byte[] packetData, int bufferLength) { if (bufferLength > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is larger than max packet size"); } if (packetData == null) { throw new InvalidOperationException("Tried to receive null packet!"); } if (bufferLength > packetData.Length) { throw new InvalidOperationException("Buffer length exceeds actual packet length!"); } byte b = packetData[0]; if ((b & 1) == 0) { byte channelID; ushort arg; ushort ack; uint ackBits; int num = PacketIO.ReadPacketHeader(packetData, 0, bufferLength, out channelID, out arg, out ack, out ackBits); bool flag; lock (receivedPackets) { flag = !receivedPackets.TestInsert(arg); } if (!flag && (b & 0x80) == 0) { if (num >= bufferLength) { throw new FormatException("Buffer too small for packet data!"); } ByteBuffer byteBuffer = ObjPool <ByteBuffer> .Get(); byteBuffer.SetSize(bufferLength - num); byteBuffer.BufferCopy(packetData, num, 0, byteBuffer.Length); config.ProcessPacketCallback(arg, byteBuffer.InternalBuffer, byteBuffer.Length); lock (receivedPackets) { ReceivedPacketData receivedPacketData = receivedPackets.Insert(arg); if (receivedPacketData == null) { throw new InvalidOperationException("Failed to insert received packet!"); } receivedPacketData.time = time; receivedPacketData.packetBytes = (uint)(config.PacketHeaderSize + bufferLength); } ObjPool <ByteBuffer> .Return(byteBuffer); } if (flag && (b & 0x80) == 0) { return; } for (int i = 0; i < 32; i++) { if ((ackBits & 1) != 0) { ushort obj = (ushort)(ack - i); SentPacketData sentPacketData = sentPackets.Find(obj); if (sentPacketData != null && !sentPacketData.acked) { sentPacketData.acked = true; if (config.AckPacketCallback != null) { config.AckPacketCallback(obj); } float num2 = (float)(time - sentPacketData.time) * 1000f; if ((rtt == 0f && num2 > 0f) || Math.Abs(rtt - num2) < 1E-05f) { rtt = num2; } else { rtt += (num2 - rtt) * config.RTTSmoothFactor; } } } ackBits >>= 1; } return; } int fragmentID; int numFragments; int fragmentBytes; ushort num3; ushort ack2; uint ackBits2; byte channelID2; int num4 = PacketIO.ReadFragmentHeader(packetData, 0, bufferLength, config.MaxFragments, config.FragmentSize, out fragmentID, out numFragments, out fragmentBytes, out num3, out ack2, out ackBits2, out channelID2); FragmentReassemblyData fragmentReassemblyData = fragmentReassembly.Find(num3); if (fragmentReassemblyData == null) { fragmentReassemblyData = fragmentReassembly.Insert(num3); if (fragmentReassemblyData == null) { return; } fragmentReassemblyData.Sequence = num3; fragmentReassemblyData.Ack = 0; fragmentReassemblyData.AckBits = 0u; fragmentReassemblyData.NumFragmentsReceived = 0; fragmentReassemblyData.NumFragmentsTotal = numFragments; fragmentReassemblyData.PacketBytes = 0; Array.Clear(fragmentReassemblyData.FragmentReceived, 0, fragmentReassemblyData.FragmentReceived.Length); } if (numFragments == fragmentReassemblyData.NumFragmentsTotal && !fragmentReassemblyData.FragmentReceived[fragmentID]) { fragmentReassemblyData.NumFragmentsReceived++; fragmentReassemblyData.FragmentReceived[fragmentID] = true; byte[] buffer = BufferPool.GetBuffer(2048); Buffer.BlockCopy(packetData, num4, buffer, 0, bufferLength - num4); fragmentReassemblyData.StoreFragmentData(channelID2, num3, ack2, ackBits2, fragmentID, config.FragmentSize, buffer, bufferLength - num4); BufferPool.ReturnBuffer(buffer); if (fragmentReassemblyData.NumFragmentsReceived == fragmentReassemblyData.NumFragmentsTotal) { ByteBuffer byteBuffer2 = ObjPool <ByteBuffer> .Get(); byteBuffer2.SetSize(fragmentReassemblyData.PacketDataBuffer.Length - fragmentReassemblyData.HeaderOffset); Buffer.BlockCopy(fragmentReassemblyData.PacketDataBuffer.InternalBuffer, fragmentReassemblyData.HeaderOffset, byteBuffer2.InternalBuffer, 0, byteBuffer2.Length); ReceivePacket(byteBuffer2.InternalBuffer, byteBuffer2.Length); ObjPool <ByteBuffer> .Return(byteBuffer2); fragmentReassemblyData.PacketDataBuffer.SetSize(0); fragmentReassembly.Remove(num3); } } }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint">The explicit endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns>The task.</returns> private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new HttpClientStream(this, clientConnection, clientConnection.GetStream(), BufferPool, cancellationToken); Task <TcpServerConnection?>?prefetchConnectionTask = null; bool closeServerConnection = false; try { TunnelConnectSessionEventArgs?connectArgs = null; var method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (method == KnownMethod.Connect) { // read the first line HTTP command var requestLine = await clientStream.ReadRequestLine(cancellationToken); if (requestLine.IsEmpty()) { return; } var connectRequest = new ConnectRequest(requestLine.RequestUri) { RequestUriString8 = requestLine.RequestUri, HttpVersion = requestLine.Version }; await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, clientStream, cancellationTokenSource); clientStream.DataRead += (o, args) => connectArgs.OnDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDataReceived(args.Buffer, args.Offset, args.Count); await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); // filter out excluded host names bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; bool sendRawData = !decryptSsl; if (connectArgs.DenyConnect) { if (connectArgs.HttpClient.Response.StatusCode == 0) { connectArgs.HttpClient.Response = new Response { HttpVersion = HttpHeader.Version11, StatusCode = (int)HttpStatusCode.Forbidden, StatusDescription = "Forbidden" }; } // send the response await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken); return; } if (await checkAuthorization(connectArgs) == false) { await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc); // send the response await clientStream.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken); return; } // write back successful CONNECT response var response = ConnectResponse.CreateSuccessfulConnectResponse(connectRequest.HttpVersion); // Set ContentLength explicitly to properly handle HTTP 1.0 response.ContentLength = 0; response.Headers.FixProxyHeaders(); connectArgs.HttpClient.Response = response; await clientStream.WriteResponseAsync(response, cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } bool isClientHello = clientHelloInfo != null; if (clientHelloInfo != null) { connectRequest.TunnelType = TunnelType.Https; connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeBeforeTunnelConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (decryptSsl && clientHelloInfo != null) { connectRequest.IsHttps = true; // todo: move this line to the previous "if" clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol; bool http2Supported = false; if (EnableHttp2) { var alpn = clientHelloInfo.GetAlpn(); if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2)) { // test server HTTP/2 support try { // todo: this is a hack, because Titanium does not support HTTP protocol changing currently var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, SslExtensions.Http2ProtocolAsList, true, true, cancellationToken); if (connection != null) { http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; // release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } } catch (Exception) { // ignore } } } if (EnableTcpServerConnectionPrefetch) { // don't pass cancellation token here // it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, true, null, false, true, CancellationToken.None); } string connectHostname = requestLine.RequestUri.GetString(); int idx = connectHostname.IndexOf(":"); if (idx >= 0) { connectHostname = connectHostname.Substring(0, idx); } X509Certificate2?certificate = null; SslStream? sslStream = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(connectHostname); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); if (EnableHttp2 && http2Supported) { options.ApplicationProtocols = clientHelloInfo.GetAlpn(); if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) { options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; } } options.ServerCertificate = certificate; options.ClientCertificateRequired = false; options.EnabledSslProtocols = SupportedSslProtocols; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; await sslStream.AuthenticateAsServerAsync(options, cancellationToken); #if NETSTANDARD2_1 clientStream.Connection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; #endif // HTTPS server created - we can now decrypt the client's traffic clientStream = new HttpClientStream(this, clientStream.Connection, sslStream, BufferPool, cancellationToken); sslStream = null; // clientStream was created, no need to keep SSL stream reference clientStream.DataRead += (o, args) => connectArgs.OnDecryptedDataSent(args.Buffer, args.Offset, args.Count); clientStream.DataWrite += (o, args) => connectArgs.OnDecryptedDataReceived(args.Buffer, args.Offset, args.Count); } catch (Exception e) { sslStream?.Dispose(); var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certName}'.", e, connectArgs); } method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } if (method == KnownMethod.Invalid) { sendRawData = true; await tcpConnectionFactory.Release(prefetchConnectionTask, true); prefetchConnectionTask = null; } } else if (clientHelloInfo == null) { method = await HttpHelper.GetMethod(clientStream, BufferPool, cancellationToken); if (clientStream.IsClosed) { return; } } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (method == KnownMethod.Invalid) { sendRawData = true; } // Hostname is excluded or it is not an HTTPS connect if (sendRawData) { // create new connection to server. // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // this connection should not be HTTPS. var connection = (await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, null, true, false, cancellationToken)) !; try { if (isClientHello) { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(); try { // clientStream.Available should be at most BufferSize because it is using the same buffer size int read = await clientStream.ReadAsync(data, 0, available, cancellationToken); if (read != available) { throw new Exception("Internal error."); } await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken); ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo; } if (!clientStream.IsClosed && !connection.Stream.IsClosed) { await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, null, null, connectArgs.CancellationTokenSource, ExceptionFunc); } } finally { await tcpConnectionFactory.Release(connection, true); } return; } } if (connectArgs != null && method == KnownMethod.Pri) { // todo string?httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (httpCmd == "PRI * HTTP/2.0") { connectArgs.HttpClient.ConnectRequest !.TunnelType = TunnelType.Http2; // HTTP/2 Connection Preface string?line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != "SM") { throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } var connection = (await tcpConnectionFactory.GetServerConnection(this, connectArgs, true, SslExtensions.Http2ProtocolAsList, true, false, cancellationToken)) !; try { #if NETSTANDARD2_1 var connectionPreface = new ReadOnlyMemory <byte>(Http2Helper.ConnectionPreface); await connection.Stream.WriteAsync(connectionPreface, cancellationToken); await Http2Helper.SendHttp2(clientStream, connection.Stream, () => new SessionEventArgs(this, endPoint, clientStream, connectArgs?.HttpClient.ConnectRequest, cancellationTokenSource) { UserData = connectArgs?.UserData }, async args => { await onBeforeRequest(args); }, async args => { await onBeforeResponse(args); }, connectArgs.CancellationTokenSource, clientStream.Connection.Id, ExceptionFunc); #endif } finally { await tcpConnectionFactory.Release(connection, true); } } } var prefetchTask = prefetchConnectionTask; prefetchConnectionTask = null; // Now create the request await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource, connectArgs, prefetchTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); clientStream.Dispose(); } }
private static IEnumerator <IAsyncResult> AsyncStreamCopyImpl(CrcStream source, CrcStream destination, long numBytes, int bufferSize, AsyncCrcStreamCopy.ComputeAndLogCrcMethod computeCrcMethodForCrcLogging, TimeSpan timeout, AsyncIteratorContext <long> context) { Exception exception; BufferWrapper buffer = null; BufferWrapper bufferWrapper = null; try { Duration startingNow = Duration.StartingNow; IAsyncResult asyncResult = null; IAsyncResult asyncResult1 = null; buffer = BufferPool.GetBuffer(bufferSize); bufferWrapper = BufferPool.GetBuffer(bufferSize); long num = (long)0; long?nullable = null; context.ResultData = (long)0; bool canTimeout = source.CanTimeout; bool flag = destination.CanTimeout; while (true) { int timeoutInMS = AsyncCrcStreamCopy.TimeSpanToTimeoutInMS(startingNow.Remaining(timeout)); if (timeoutInMS == 0) { throw new TimeoutException("The asynchronous stream copy timed out."); } if (canTimeout) { try { source.ReadTimeout = timeoutInMS; } catch (InvalidOperationException invalidOperationException) { canTimeout = false; } } if (flag) { try { destination.WriteTimeout = timeoutInMS; } catch (InvalidOperationException invalidOperationException1) { flag = false; } } if (numBytes > (long)0) { asyncResult = source.BeginRead(buffer.Buffer, 0, (int)Math.Min((long)((int)buffer.Buffer.Length), numBytes), context.GetResumeCallback(), context.GetResumeState("AsyncCrcStreamCopy.source.Read")); } exception = null; if (num > (long)0) { try { asyncResult1 = destination.BeginWrite(bufferWrapper.Buffer, 0, (int)num, nullable, context.GetResumeCallback(), context.GetResumeState("AsyncCrcStreamCopy.dest.Write")); } catch (Exception exception1) { exception = exception1; } if (exception == null) { yield return(asyncResult1); try { destination.EndWrite(asyncResult1); } catch (Exception exception2) { exception = exception2; } } } if (numBytes <= (long)0) { num = (long)0; } else { yield return(asyncResult); num = (long)source.EndRead(out nullable, asyncResult); } if (exception != null) { throw ExceptionCloner.AttemptClone(exception, RethrowableWrapperBehavior.NoWrap); } if (num < (long)0) { break; } numBytes -= num; AsyncIteratorContext <long> resultData = context; resultData.ResultData = resultData.ResultData + num; if (computeCrcMethodForCrcLogging != null) { computeCrcMethodForCrcLogging(buffer.Buffer, 0, (int)num, context.ResultData); } AsyncCrcStreamCopy.Swap <BufferWrapper>(ref buffer, ref bufferWrapper); if (num <= (long)0) { goto Label2; } } throw new TimeoutException("Reading from the stream resulted in a negative number of bytes read. This typically means an HttpWebRequest was aborted."); } finally { if (buffer != null) { BufferPool.ReleaseBuffer(buffer); } if (bufferWrapper != null) { BufferPool.ReleaseBuffer(bufferWrapper); } } Label2: yield break; throw new TimeoutException("The asynchronous stream copy timed out."); throw ExceptionCloner.AttemptClone(exception, RethrowableWrapperBehavior.NoWrap); }
// process an incoming connection request packet private void processConnectionRequest(ByteArrayReaderWriter reader, int size, EndPoint sender) { log("Got connection request", NetcodeLogLevel.Debug); var connectionRequestPacket = new NetcodeConnectionRequestPacket(); if (!connectionRequestPacket.Read(reader, size - (int)reader.ReadPosition, protocolID)) { log("Failed to read request", NetcodeLogLevel.Debug); return; } // expiration timestamp should be greater than current timestamp if (connectionRequestPacket.Expiration <= (ulong)Math.Truncate(time)) { log("Connect token expired", NetcodeLogLevel.Debug); connectionRequestPacket.Release(); return; } var privateConnectToken = new NetcodePrivateConnectToken(); if (!privateConnectToken.Read(connectionRequestPacket.ConnectTokenBytes, privateKey, protocolID, connectionRequestPacket.Expiration, connectionRequestPacket.TokenSequenceNum)) { log("Failed to read private token", NetcodeLogLevel.Debug); connectionRequestPacket.Release(); return; } // if this server's public IP is not in the list of endpoints, packet is not valid bool serverAddressInEndpoints = privateConnectToken.ConnectServers.Any(x => x.Endpoint.CompareEndpoint(this.listenEndpoint, this.Port)); if (!serverAddressInEndpoints) { log("Server address not listen in token", NetcodeLogLevel.Debug); return; } // if a client from packet source IP / port is already connected, ignore the packet if (clientSlots.Any(x => x != null && x.RemoteEndpoint.Equals(sender))) { log("Client {0} already connected", NetcodeLogLevel.Debug, sender.ToString()); return; } // if a client with the same id as the connect token is already connected, ignore the packet if (clientSlots.Any(x => x != null && x.ClientID == privateConnectToken.ClientID)) { log("Client ID {0} already connected", NetcodeLogLevel.Debug, privateConnectToken.ClientID); return; } // if the connect token has already been used by a different endpoint, ignore the packet // otherwise, add the token hmac and endpoint to the used token history // compares the last 16 bytes (token mac) byte[] token_mac = BufferPool.GetBuffer(Defines.MAC_SIZE); System.Array.Copy(connectionRequestPacket.ConnectTokenBytes, Defines.NETCODE_CONNECT_TOKEN_PRIVATE_BYTES - Defines.MAC_SIZE, token_mac, 0, Defines.MAC_SIZE); if (!findOrAddConnectToken(sender, token_mac, time)) { log("Token already used", NetcodeLogLevel.Debug); BufferPool.ReturnBuffer(token_mac); return; } BufferPool.ReturnBuffer(token_mac); // if we have no slots, we need to respond with a connection denied packet var nextSlot = getFreeClientSlot(); if (nextSlot == -1) { denyConnection(sender, privateConnectToken.ServerToClientKey); log("Server is full, denying connection", NetcodeLogLevel.Info); return; } // add encryption mapping for this endpoint as well as timeout // packets received from this endpoint are to be decrypted with the client-to-server key // packets sent to this endpoint are to be encrypted with the server-to-client key // if no messages are received within timeout from this endpoint, it is disconnected (unless timeout is negative) if (!encryptionManager.AddEncryptionMapping(sender, privateConnectToken.ServerToClientKey, privateConnectToken.ClientToServerKey, time, time + 30, privateConnectToken.TimeoutSeconds, 0)) { log("Failed to add encryption mapping", NetcodeLogLevel.Error); return; } // finally, send a connection challenge packet sendConnectionChallenge(privateConnectToken, sender); }
public static int Decrypt(byte[] ciphertext, int offset, int len, byte[] additionalData, byte[] nonce, byte[] key, byte[] outBuffer) { lock (mutex) { if (cipher == null) { cipher = new ChaCha7539Engine(); } else { cipher.Reset(); } if (_decryptKey == null) { _decryptKey = new KeyParameter(key); } else { _decryptKey.Reset(); _decryptKey.SetKey(key); } if (_temp_Params == null) { _temp_Params = new ParametersWithIV(_decryptKey, nonce); } else { _temp_Params.Reset(); _temp_Params.Set(_decryptKey, nonce); } cipher.Init(false, _temp_Params); byte[] firstBlock = BufferPool.GetBuffer(64); KeyParameter macKey = GenerateRecordMacKey(cipher, firstBlock); int plaintextLength = len - 16; byte[] calculatedMac = BufferPool.GetBuffer(16); CalculateRecordMac(macKey, additionalData, ciphertext, offset, plaintextLength, calculatedMac); byte[] receivedMac = BufferPool.GetBuffer(16); Array.Copy(ciphertext, offset + plaintextLength, receivedMac, 0, receivedMac.Length); if (!Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac)) { BufferPool.ReturnBuffer(calculatedMac); BufferPool.ReturnBuffer(receivedMac); BufferPool.ReturnBuffer(firstBlock); throw new TlsFatalAlert(AlertDescription.bad_record_mac); } BufferPool.ReturnBuffer(calculatedMac); BufferPool.ReturnBuffer(receivedMac); BufferPool.ReturnBuffer(firstBlock); cipher.ProcessBytes(ciphertext, offset, plaintextLength, outBuffer, 0); return(plaintextLength); } }
/////////////////////////////////////////////////////////////////////////// /// <summary> /// 构造函数 /// </summary> /// <param name="ms">目标内存流</param> public luaProtoWriter(MemoryStream ms) { _stream = ms; _buff = BufferPool.GetBuffer(); }
public void Set(ICipherParameters parameters, byte[] iv) { this.parameters = parameters; this.iv = BufferPool.GetBuffer(iv.Length); Array.Copy(iv, 0, this.iv, 0, this.iv.Length); }
/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, cancellationToken); bool isHttps = clientHelloInfo != null; string httpsHostName = null; if (isHttps) { httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource) { SniHostName = httpsHostName }; await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (endPoint.DecryptSsl && args.DecryptSsl) { SslStream sslStream = null; try { sslStream = new SslStream(clientStream); string certName = HttpHelper.GetWildCardDomainName(httpsHostName); var certificate = await CertificateManager.CreateCertificateAsync(certName); // Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); } catch (Exception e) { sslStream?.Dispose(); throw new ProxyConnectException( $"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e, null); } } else { // create new connection var connection = new TcpClient(UpStreamEndPoint); await connection.ConnectAsync(httpsHostName, endPoint.Port); connection.ReceiveTimeout = ConnectionTimeOutSeconds * 1000; connection.SendTimeout = ConnectionTimeOutSeconds * 1000; using (connection) { var serverStream = connection.GetStream(); int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { // clientStream.Available sbould be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available, cancellationToken); await serverStream.WriteAsync(data, 0, available, cancellationToken); await serverStream.FlushAsync(cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } ////var serverHelloInfo = await SslTools.PeekServerHello(serverStream); await TcpHelper.SendRaw(clientStream, serverStream, BufferSize, null, null, cancellationTokenSource, ExceptionFunc); } } } // HTTPS server created - we can now decrypt the client's traffic // Now create the request await HandleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, isHttps?httpsHostName : null, null); } catch (ProxyException e) { OnException(clientStream, e); } catch (IOException e) { OnException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { OnException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { OnException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
private static void SpinFileReaders(BlockingCollection <ReadFileWork> readFileWork, BlockingCollection <CrcComputationWork> crcComputationWork) { // These I/O Actors allows us to parallelize all the I/O work. On slow / cloud machines, that allows the I/O subsystem to get // bulk read speed from the underlying systems. for (int i = 0; i < Environment.ProcessorCount; i++) { Task.Factory.StartNew(() => { while (!readFileWork.IsCompleted) { ReadFileWork work = null; if (!readFileWork.TryTake(out work, 20)) { continue; } var fileInfo = new FileInfo(work.FileName); // some buffers can be very large, we will use consistent 16KB buffers // and if the file is too large, we will use multiple 16KB buffers. // For a file that is 260 KB (jQuery 1.8.3 is 261.46 KB) in size, that means we will use 272 KB only, // versus the 512KB we would use if we used a power of two approach. // So we'll waste only 12KB instead of 252KB var buffers = new List <byte[]>(); try { const int bufferSize = 16 * 1024; using (var fs = fileInfo.OpenRead()) { for (int j = 0; j < fileInfo.Length; j += bufferSize) { var buffer = BufferPool.GetBuffer(bufferSize); buffers.Add(buffer); // we can't call fs.Read here, it will allocate a 4KB buffer that will then be discarded. // so we use the native ReadFile method and read directly to our pooled buffer int read; if (ReadFile(fs.SafeFileHandle, buffer, buffer.Length, out read, IntPtr.Zero) == false) { throw new Win32Exception(); } } } } catch (Exception) { // If there has ben any error in reading from the file or opening it, we've have // to make sure that we won't forget about this buffer. Even with the error that just // happened, we can still make use of it. foreach (var buffer in buffers) { BufferPool.ReturnBuffer(buffer); } throw; } crcComputationWork.Add(new CrcComputationWork { Length = (int)fileInfo.Length, Buffers = buffers, // the SpinCrcComputations will be returning the bufer to the ppol FileName = work.FileName }); } _countDown.Signal(); }); } }
public void ReceivePacket(byte[] packetData, int bufferLength) { if (bufferLength > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is larger than max packet size"); } byte prefixByte = packetData[0]; if ((prefixByte & 1) == 0) { // regular packet ushort sequence; ushort ack; uint ackBits; byte channelID; int packetHeaderBytes = PacketIO.ReadPacketHeader(packetData, 0, bufferLength, out channelID, out sequence, out ack, out ackBits); bool isStale = !receivedPackets.TestInsert(sequence); if (!isStale && (prefixByte & 0x80) == 0) { ByteBuffer tempBuffer = ObjPool <ByteBuffer> .Get(); tempBuffer.SetSize(bufferLength - packetHeaderBytes); tempBuffer.BufferCopy(packetData, packetHeaderBytes, 0, tempBuffer.Length); // process packet config.ProcessPacketCallback(sequence, tempBuffer.InternalBuffer, tempBuffer.Length); // add to received buffer ReceivedPacketData receivedPacketData = receivedPackets.Insert(sequence); receivedPacketData.time = this.time; receivedPacketData.packetBytes = (uint)(config.PacketHeaderSize + bufferLength); ObjPool <ByteBuffer> .Return(tempBuffer); } if (!isStale || (prefixByte & 0x80) != 0) { for (int i = 0; i < 32; i++) { if ((ackBits & 1) != 0) { ushort ack_sequence = (ushort)(ack - i); SentPacketData sentPacketData = sentPackets.Find(ack_sequence); if (sentPacketData != null && !sentPacketData.acked) { sentPacketData.acked = true; if (config.AckPacketCallback != null) { config.AckPacketCallback(ack_sequence); } float rtt = (float)(this.time - sentPacketData.time) * 1000.0f; if ((this.rtt == 0f && rtt > 0f) || Math.Abs(this.rtt - rtt) < 0.00001f) { this.rtt = rtt; } else { this.rtt += (rtt - this.rtt) * config.RTTSmoothFactor; } } } ackBits >>= 1; } } } else { // fragment packet int fragmentID; int numFragments; int fragmentBytes; ushort sequence; ushort ack; uint ackBits; byte fragmentChannelID; int fragmentHeaderBytes = PacketIO.ReadFragmentHeader(packetData, 0, bufferLength, config.MaxFragments, config.FragmentSize, out fragmentID, out numFragments, out fragmentBytes, out sequence, out ack, out ackBits, out fragmentChannelID); FragmentReassemblyData reassemblyData = fragmentReassembly.Find(sequence); if (reassemblyData == null) { reassemblyData = fragmentReassembly.Insert(sequence); // failed to insert into buffer (stale) if (reassemblyData == null) { return; } reassemblyData.Sequence = sequence; reassemblyData.Ack = 0; reassemblyData.AckBits = 0; reassemblyData.NumFragmentsReceived = 0; reassemblyData.NumFragmentsTotal = numFragments; reassemblyData.PacketBytes = 0; Array.Clear(reassemblyData.FragmentReceived, 0, reassemblyData.FragmentReceived.Length); } if (numFragments != reassemblyData.NumFragmentsTotal) { return; } if (reassemblyData.FragmentReceived[fragmentID]) { return; } reassemblyData.NumFragmentsReceived++; reassemblyData.FragmentReceived[fragmentID] = true; byte[] tempFragmentData = BufferPool.GetBuffer(2048); Buffer.BlockCopy(packetData, fragmentHeaderBytes, tempFragmentData, 0, bufferLength - fragmentHeaderBytes); reassemblyData.StoreFragmentData(fragmentChannelID, sequence, ack, ackBits, fragmentID, config.FragmentSize, tempFragmentData, bufferLength - fragmentHeaderBytes); BufferPool.ReturnBuffer(tempFragmentData); if (reassemblyData.NumFragmentsReceived == reassemblyData.NumFragmentsTotal) { // grab internal buffer and pass it to ReceivePacket. Internal buffer will be packet marked as normal packet, so it will go through normal packet path this.ReceivePacket(reassemblyData.PacketDataBuffer.InternalBuffer, reassemblyData.PacketDataBuffer.Length); reassemblyData.PacketDataBuffer.SetSize(0); fragmentReassembly.Remove(sequence); } } }
internal static byte[] Serialize(GsWriteStream writeStream) { var(bufferSize, objectInfos) = GetInfos(writeStream); var packetBuffer = BufferPool.GetBuffer(bufferSize); using (var packetWriter = ByteArrayReaderWriter.Get(packetBuffer)) { packetWriter.Write((byte)objectInfos.Count); foreach (var objectInfo in objectInfos) { packetWriter.Write((byte)objectInfo.Type); switch (objectInfo.Type) { case Types.Byte: packetWriter.Write((byte)objectInfo.Src); break; case Types.Char: packetWriter.Write((char)objectInfo.Src); break; case Types.Double: packetWriter.Write(BitConverter.GetBytes((double)objectInfo.Src)); break; case Types.Float: packetWriter.Write(BitConverter.GetBytes((float)objectInfo.Src)); break; case Types.Int: packetWriter.Write((int)objectInfo.Src); break; case Types.Long: packetWriter.Write((long)objectInfo.Src); break; case Types.Short: packetWriter.Write((short)objectInfo.Src); break; case Types.Uint: packetWriter.Write((uint)objectInfo.Src); break; case Types.Ushort: packetWriter.Write((ushort)objectInfo.Src); break; case Types.Ulong: packetWriter.Write((ulong)objectInfo.Src); break; case Types.Bool: byte data = 0x0; if ((bool)objectInfo.Src) { data = 0x1; } packetWriter.Write(data); break; case Types.CustomObject: var bufferDataObject = (byte[])objectInfo.Src; packetWriter.Write((int)objectInfo.Extra); packetWriter.Write((ushort)bufferDataObject.Length); packetWriter.Write(bufferDataObject); break; case Types.String: case Types.ByteArray: case Types.CharArray: case Types.DoubleArray: case Types.FloatArray: case Types.IntArray: case Types.LongArray: case Types.StringArray: var bArray = (byte[])objectInfo.Src; packetWriter.Write((ushort)bArray.Length); packetWriter.Write(bArray); break; case Types.Null: break; default: throw new ArgumentOutOfRangeException(); } } } return(packetBuffer); }
/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); SslStream sslStream = null; try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); bool isHttps = clientHelloInfo != null; string httpsHostName = null; if (isHttps) { httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource) { SniHostName = httpsHostName }; await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (endPoint.DecryptSsl && args.DecryptSsl) { //do client authentication using certificate X509Certificate2 certificate = null; try { sslStream = new SslStream(clientStream, true); string certName = HttpHelper.GetWildCardDomainName(httpsHostName); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); } catch (Exception e) { var certname = certificate?.GetNameInfo(X509NameType.SimpleName, false); var session = new SessionEventArgs(this, endPoint, cancellationTokenSource) { ProxyClient = { Connection = clientConnection }, HttpClient = { ConnectRequest = null } }; throw new ProxyConnectException( $"Couldn't authenticate host '{httpsHostName}' with certificate '{certname}'.", e, session); } } else { var connection = await tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, httpVersion : null, isHttps : false, applicationProtocols : null, isConnect : true, proxyServer : this, session : null, upStreamEndPoint : UpStreamEndPoint, externalProxy : UpStreamHttpsProxy, noCache : true, cancellationToken : cancellationToken); try { CustomBufferedStream serverStream = null; int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { // clientStream.Available sbould be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available, cancellationToken); serverStream = connection.Stream; await serverStream.WriteAsync(data, 0, available, cancellationToken); await serverStream.FlushAsync(cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize, null, null, cancellationTokenSource, ExceptionFunc); } finally { await tcpConnectionFactory.Release(connection, true); } return; } } // HTTPS server created - we can now decrypt the client's traffic // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, isHttps?httpsHostName : null, null, null); } catch (ProxyException e) { onException(clientStream, e); } catch (IOException e) { onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { sslStream?.Dispose(); clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private async Task handleClient(SocksProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var stream = clientConnection.GetStream(); var buffer = BufferPool.GetBuffer(); int port = 0; try { int read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken); if (read < 3) { return; } if (buffer[0] == 4) { if (read < 9 || buffer[1] != 1) { // not a connect request return; } port = (buffer[2] << 8) + buffer[3]; buffer[0] = 0; buffer[1] = 90; // request granted await stream.WriteAsync(buffer, 0, 8, cancellationToken); } else if (buffer[0] == 5) { int authenticationMethodCount = buffer[1]; if (read < authenticationMethodCount + 2) { return; } int acceptedMethod = 255; for (int i = 0; i < authenticationMethodCount; i++) { int method = buffer[i + 2]; if (method == 0 && ProxyBasicAuthenticateFunc == null) { acceptedMethod = 0; break; } if (method == 2) { acceptedMethod = 2; break; } } buffer[1] = (byte)acceptedMethod; await stream.WriteAsync(buffer, 0, 2, cancellationToken); if (acceptedMethod == 255) { // no acceptable method return; } if (acceptedMethod == 2) { read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken); if (read < 3 || buffer[0] != 1) { // authentication version should be 1 return; } int userNameLength = buffer[1]; if (read < 3 + userNameLength) { return; } string userName = Encoding.ASCII.GetString(buffer, 2, userNameLength); int passwordLength = buffer[2 + userNameLength]; if (read < 3 + userNameLength + passwordLength) { return; } string password = Encoding.ASCII.GetString(buffer, 3 + userNameLength, passwordLength); bool success = true; if (ProxyBasicAuthenticateFunc != null) { success = await ProxyBasicAuthenticateFunc.Invoke(null, userName, password); } buffer[1] = success ? (byte)0 : (byte)1; await stream.WriteAsync(buffer, 0, 2, cancellationToken); if (!success) { return; } } read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken); if (read < 10 || buffer[1] != 1) { return; } int portIdx; switch (buffer[3]) { case 1: // IPv4 portIdx = 8; break; case 3: // Domainname portIdx = buffer[4] + 5; #if DEBUG var hostname = new ByteString(buffer.AsMemory(5, buffer[4])); string hostnameStr = hostname.GetString(); #endif break; case 4: // IPv6 portIdx = 20; break; default: return; } if (read < portIdx + 2) { return; } port = (buffer[portIdx] << 8) + buffer[portIdx + 1]; buffer[1] = 0; // succeeded await stream.WriteAsync(buffer, 0, read, cancellationToken); } else { return; } } finally { BufferPool.ReturnBuffer(buffer); } await handleClient(endPoint, clientConnection, port, cancellationTokenSource, cancellationToken); }
public ushort SendPacket(byte[] packetData, int length, byte channelID) { if (length > config.MaxPacketSize) { throw new ArgumentOutOfRangeException("Packet is too large to send, max packet size is " + config.MaxPacketSize + " bytes"); } ushort num = sequence++; ushort ack; uint ackBits; lock (receivedPackets) { receivedPackets.GenerateAckBits(out ack, out ackBits); } SentPacketData sentPacketData = sentPackets.Insert(num); sentPacketData.time = time; sentPacketData.packetBytes = (uint)(config.PacketHeaderSize + length); sentPacketData.acked = false; if (length <= config.FragmentThreshold) { byte[] buffer = BufferPool.GetBuffer(2048); int num2 = PacketIO.WritePacketHeader(buffer, channelID, num, ack, ackBits); int arg = length + num2; Buffer.BlockCopy(packetData, 0, buffer, num2, length); config.TransmitPacketCallback(buffer, arg); BufferPool.ReturnBuffer(buffer); } else { byte[] buffer2 = BufferPool.GetBuffer(10); int num3 = 0; try { num3 = PacketIO.WritePacketHeader(buffer2, channelID, num, ack, ackBits); } catch { throw; } int num4 = length / config.FragmentSize + ((length % config.FragmentSize != 0) ? 1 : 0); byte[] buffer3 = BufferPool.GetBuffer(2048); int num5 = 0; byte b = 1; b = (byte)(b | (byte)((channelID & 3) << 6)); for (int i = 0; i < num4; i++) { using (ByteArrayReaderWriter byteArrayReaderWriter = ByteArrayReaderWriter.Get(buffer3)) { byteArrayReaderWriter.Write(b); byteArrayReaderWriter.Write(channelID); byteArrayReaderWriter.Write(num); byteArrayReaderWriter.Write((byte)i); byteArrayReaderWriter.Write((byte)(num4 - 1)); if (i == 0) { byteArrayReaderWriter.WriteBuffer(buffer2, num3); } int num6 = config.FragmentSize; if (num5 + num6 > length) { num6 = length - num5; } for (int j = 0; j < num6; j++) { byteArrayReaderWriter.Write(packetData[num5++]); } int arg2 = (int)byteArrayReaderWriter.WritePosition; config.TransmitPacketCallback(buffer3, arg2); } } BufferPool.ReturnBuffer(buffer2); BufferPool.ReturnBuffer(buffer3); } return(num); }
internal byte[] Serialize() { byte havePayload = 0x0, haveExtra = 0x0, haveSender = 0x0, haveReceiver = 0x0; short prefixLen = 4 * sizeof(byte); if (Payload != null) { havePayload = 0x1; _payloadLen = Payload.Length; prefixLen += sizeof(ushort); } if (ExtraData != null) { haveExtra = 0x1; _extraLen = ExtraData.Length; prefixLen += sizeof(ushort); } if (SenderId != null) { haveSender = 0x1; _senderLen = SenderId.Length; prefixLen += sizeof(byte); } if (ReceiverId != null) { haveReceiver = 0x1; _receiverLen = ReceiverId.Length; prefixLen += sizeof(byte); } var packetBuffer = BufferPool.GetBuffer(BufferSize(prefixLen)); using (var packetWriter = ByteArrayReaderWriter.Get(packetBuffer)) { // header Segment packetWriter.Write(haveSender); packetWriter.Write(haveReceiver); packetWriter.Write(havePayload); packetWriter.Write(haveExtra); if (haveSender == 0x1) { packetWriter.Write((byte)_senderLen); } if (haveReceiver == 0x1) { packetWriter.Write((byte)_receiverLen); } if (havePayload == 0x1) { packetWriter.Write((ushort)_payloadLen); } if (haveExtra == 0x1) { packetWriter.Write((ushort)_extraLen); } // data Segment if (haveSender == 0x1) { packetWriter.Write(ConvertToBytes(SenderId)); } if (haveReceiver == 0x1) { packetWriter.Write(ConvertToBytes(ReceiverId)); } if (havePayload == 0x1) { packetWriter.Write(Payload); } if (haveExtra == 0x1) { packetWriter.Write(ExtraData); } } return(packetBuffer); }
/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new HttpClientStream(clientConnection, clientConnection.GetStream(), BufferPool); SslStream?sslStream = null; try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); if (clientHelloInfo != null) { var httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; var args = new BeforeSslAuthenticateEventArgs(clientConnection, cancellationTokenSource, httpsHostName); await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (endPoint.DecryptSsl && args.DecryptSsl) { clientStream.Connection.SslProtocol = clientHelloInfo.SslProtocol; // do client authentication using certificate X509Certificate2?certificate = null; try { sslStream = new SslStream(clientStream, false); string certName = HttpHelper.GetWildCardDomainName(httpsHostName); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic clientStream = new HttpClientStream(clientStream.Connection, sslStream, BufferPool); sslStream = null; // clientStream was created, no need to keep SSL stream reference } catch (Exception e) { var certName = certificate?.GetNameInfo(X509NameType.SimpleName, false); var session = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource); throw new ProxyConnectException( $"Couldn't authenticate host '{httpsHostName}' with certificate '{certName}'.", e, session); } } else { var sessionArgs = new SessionEventArgs(this, endPoint, clientStream, null, cancellationTokenSource); var connection = await tcpConnectionFactory.GetServerConnection(this, httpsHostName, endPoint.Port, HttpHeader.VersionUnknown, false, null, true, sessionArgs, UpStreamEndPoint, UpStreamHttpsProxy, true, cancellationToken); try { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(); try { // clientStream.Available should be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available, cancellationToken); await connection.Stream.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } if (!clientStream.IsClosed && !connection.Stream.IsClosed) { await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, null, null, cancellationTokenSource, ExceptionFunc); } } finally { await tcpConnectionFactory.Release(connection, true); } return; } } // HTTPS server created - we can now decrypt the client's traffic // Now create the request await handleHttpSessionRequest(endPoint, clientStream, cancellationTokenSource); } catch (ProxyException e) { onException(clientStream, e); } catch (IOException e) { onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { sslStream?.Dispose(); clientStream.Dispose(); } }
/// <summary> /// This is called when this proxy acts as a reverse proxy (like a real http server). /// So for HTTPS requests we would start SSL negotiation right away without expecting a CONNECT request from client /// </summary> /// <param name="endPoint">The transparent endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns></returns> private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); Task <TcpServerConnection> prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); bool isHttps = clientHelloInfo != null; string httpsHostName = null; if (isHttps) { httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName; var args = new BeforeSslAuthenticateEventArgs(cancellationTokenSource) { SniHostName = httpsHostName }; await endPoint.InvokeBeforeSslAuthenticate(this, args, ExceptionFunc); if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } if (endPoint.DecryptSsl && args.DecryptSsl) { //don't pass cancellation token here //it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetClient(httpsHostName, endPoint.Port, null, true, null, false, this, UpStreamEndPoint, UpStreamHttpsProxy, false, CancellationToken.None); SslStream sslStream = null; //do client authentication using fake certificate try { sslStream = new SslStream(clientStream); string certName = HttpHelper.GetWildCardDomainName(httpsHostName); var certificate = await CertificateManager.CreateCertificateAsync(certName); // Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); } catch (Exception e) { sslStream?.Dispose(); throw new ProxyConnectException( $"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e, null); } } else { var connection = await tcpConnectionFactory.GetClient(httpsHostName, endPoint.Port, null, false, null, true, this, UpStreamEndPoint, UpStreamHttpsProxy, true, cancellationToken); try { CustomBufferedStream serverStream = null; int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { // clientStream.Available sbould be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available, cancellationToken); serverStream = connection.Stream; await serverStream.WriteAsync(data, 0, available, cancellationToken); await serverStream.FlushAsync(cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize, null, null, cancellationTokenSource, ExceptionFunc); } finally { await tcpConnectionFactory.Release(connection, true); } return; } } calledRequestHandler = true; // HTTPS server created - we can now decrypt the client's traffic // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, isHttps?httpsHostName : null, null, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!calledRequestHandler && prefetchConnectionTask != null) { var connection = await prefetchConnectionTask; await tcpConnectionFactory.Release(connection, closeServerConnection); } clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint">The explicit endpoint.</param> /// <param name="clientConnection">The client connection.</param> /// <returns>The task.</returns> private async Task handleClient(ExplicitProxyEndPoint endPoint, TcpClientConnection clientConnection) { var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(this.cancellationTokenSource.Token); var cancellationToken = cancellationTokenSource.Token; var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); Task <TcpServerConnection> prefetchConnectionTask = null; bool closeServerConnection = false; bool calledRequestHandler = false; SslStream sslStream = null; try { string connectHostname = null; TunnelConnectSessionEventArgs connectArgs = null; // Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (await HttpHelper.IsConnectMethod(clientStream) == 1) { // read the first line HTTP command string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (string.IsNullOrEmpty(httpCmd)) { return; } Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version); var httpRemoteUri = new Uri("http://" + httpUrl); connectHostname = httpRemoteUri.Host; var connectRequest = new ConnectRequest { RequestUri = httpRemoteUri, OriginalUrl = httpUrl, HttpVersion = version }; await HeaderParser.ReadHeaders(clientStream, connectRequest.Headers, cancellationToken); connectArgs = new TunnelConnectSessionEventArgs(this, endPoint, connectRequest, cancellationTokenSource); connectArgs.ProxyClient.Connection = clientConnection; connectArgs.ProxyClient.ClientStream = clientStream; await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc); // filter out excluded host names bool decryptSsl = endPoint.DecryptSsl && connectArgs.DecryptSsl; if (connectArgs.DenyConnect) { if (connectArgs.HttpClient.Response.StatusCode == 0) { connectArgs.HttpClient.Response = new Response { HttpVersion = HttpHeader.Version11, StatusCode = (int)HttpStatusCode.Forbidden, StatusDescription = "Forbidden" }; } // send the response await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken : cancellationToken); return; } if (await checkAuthorization(connectArgs) == false) { await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc); // send the response await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, cancellationToken : cancellationToken); return; } // write back successful CONNECT response var response = ConnectResponse.CreateSuccessfulConnectResponse(version); // Set ContentLength explicitly to properly handle HTTP 1.0 response.ContentLength = 0; response.Headers.FixProxyHeaders(); connectArgs.HttpClient.Response = response; await clientStreamWriter.WriteResponseAsync(response, cancellationToken : cancellationToken); var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); bool isClientHello = clientHelloInfo != null; if (isClientHello) { connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeBeforeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (decryptSsl && isClientHello) { connectRequest.RequestUri = new Uri("https://" + httpUrl); bool http2Supported = false; var alpn = clientHelloInfo.GetAlpn(); if (alpn != null && alpn.Contains(SslApplicationProtocol.Http2)) { // test server HTTP/2 support // todo: this is a hack, because Titanium does not support HTTP protocol changing currently var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); http2Supported = connection.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2; //release connection back to pool instead of closing when connection pool is enabled. await tcpConnectionFactory.Release(connection, true); } if (EnableTcpServerConnectionPrefetch) { IPAddress[] ipAddresses = null; try { //make sure the host can be resolved before creating the prefetch task ipAddresses = await Dns.GetHostAddressesAsync(connectArgs.HttpClient.Request.RequestUri.Host); } catch (SocketException) { } if (ipAddresses != null && ipAddresses.Length > 0) { //don't pass cancellation token here //it could cause floating server connections when client exits prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect: true, applicationProtocols: null, noCache: false, cancellationToken: CancellationToken.None); } } X509Certificate2 certificate = null; try { sslStream = new SslStream(clientStream, true); string certName = HttpHelper.GetWildCardDomainName(connectHostname); certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); if (http2Supported) { options.ApplicationProtocols = clientHelloInfo.GetAlpn(); if (options.ApplicationProtocols == null || options.ApplicationProtocols.Count == 0) { options.ApplicationProtocols = SslExtensions.Http11ProtocolAsList; } } options.ServerCertificate = certificate; options.ClientCertificateRequired = false; options.EnabledSslProtocols = SupportedSslProtocols; options.CertificateRevocationCheckMode = X509RevocationMode.NoCheck; await sslStream.AuthenticateAsServerAsync(options, cancellationToken); #if NETCOREAPP2_1 clientConnection.NegotiatedApplicationProtocol = sslStream.NegotiatedApplicationProtocol; #endif // HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferPool, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); } catch (Exception e) { var certname = certificate?.GetNameInfo(X509NameType.SimpleName, false); throw new ProxyConnectException( $"Couldn't authenticate host '{connectHostname}' with certificate '{certname}'.", e, connectArgs); } if (await HttpHelper.IsConnectMethod(clientStream) == -1) { decryptSsl = false; } if (!decryptSsl) { await tcpConnectionFactory.Release(prefetchConnectionTask, true); prefetchConnectionTask = null; } } if (cancellationTokenSource.IsCancellationRequested) { throw new Exception("Session was terminated by user."); } // Hostname is excluded or it is not an HTTPS connect if (!decryptSsl || !isClientHello) { // create new connection to server. // If we detected that client tunnel CONNECTs without SSL by checking for empty client hello then // this connection should not be HTTPS. var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); try { if (isClientHello) { int available = clientStream.Available; if (available > 0) { // send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { await clientStream.ReadAsync(data, 0, available, cancellationToken); // clientStream.Available should be at most BufferSize because it is using the same buffer size await connection.StreamWriter.WriteAsync(data, 0, available, true, cancellationToken); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream, BufferPool, cancellationToken); ((ConnectResponse)connectArgs.HttpClient.Response).ServerHelloInfo = serverHelloInfo; } await TcpHelper.SendRaw(clientStream, connection.Stream, BufferPool, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, connectArgs.CancellationTokenSource, ExceptionFunc); } finally { await tcpConnectionFactory.Release(connection, true); } return; } } if (connectArgs != null && await HttpHelper.IsPriMethod(clientStream) == 1) { // todo string httpCmd = await clientStream.ReadLineAsync(cancellationToken); if (httpCmd == "PRI * HTTP/2.0") { // HTTP/2 Connection Preface string line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != "SM") { throw new Exception($"HTTP/2 Protocol violation. 'SM' expected, '{line}' received"); } line = await clientStream.ReadLineAsync(cancellationToken); if (line != string.Empty) { throw new Exception($"HTTP/2 Protocol violation. Empty string expected, '{line}' received"); } var connection = await tcpConnectionFactory.GetServerConnection(this, connectArgs, isConnect : true, applicationProtocols : SslExtensions.Http2ProtocolAsList, noCache : true, cancellationToken : cancellationToken); try { await connection.StreamWriter.WriteLineAsync("PRI * HTTP/2.0", cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken); await connection.StreamWriter.WriteLineAsync("SM", cancellationToken); await connection.StreamWriter.WriteLineAsync(cancellationToken); #if NETCOREAPP2_1 await Http2Helper.SendHttp2(clientStream, connection.Stream, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, connectArgs.CancellationTokenSource, clientConnection.Id, ExceptionFunc); #endif } finally { await tcpConnectionFactory.Release(connection, true); } } } calledRequestHandler = true; // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, cancellationTokenSource, connectHostname, connectArgs, prefetchConnectionTask); } catch (ProxyException e) { closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { if (!calledRequestHandler) { await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); } sslStream?.Dispose(); clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } } }
/// <summary> /// This is called when client is aware of proxy /// So for HTTPS requests client would send CONNECT header to negotiate a secure tcp tunnel via proxy /// </summary> /// <param name="endPoint"></param> /// <param name="tcpClient"></param> /// <returns></returns> private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpClient) { var clientStream = new CustomBufferedStream(tcpClient.GetStream(), BufferSize); var clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); try { string connectHostname = null; ConnectRequest connectRequest = null; //Client wants to create a secure tcp tunnel (probably its a HTTPS or Websocket request) if (await HttpHelper.IsConnectMethod(clientStream) == 1) { //read the first line HTTP command string httpCmd = await clientStreamReader.ReadLineAsync(); if (string.IsNullOrEmpty(httpCmd)) { return; } Request.ParseRequestLine(httpCmd, out string _, out string httpUrl, out var version); var httpRemoteUri = new Uri("http://" + httpUrl); connectHostname = httpRemoteUri.Host; //filter out excluded host names bool excluded = false; if (endPoint.ExcludedHttpsHostNameRegex != null) { excluded = endPoint.ExcludedHttpsHostNameRegexList.Any(x => x.IsMatch(connectHostname)); } if (endPoint.IncludedHttpsHostNameRegex != null) { excluded = !endPoint.IncludedHttpsHostNameRegexList.Any(x => x.IsMatch(connectHostname)); } if (endPoint.BeforeTunnelConnect != null) { excluded = await endPoint.BeforeTunnelConnect(connectHostname); } connectRequest = new ConnectRequest { RequestUri = httpRemoteUri, OriginalUrl = httpUrl, HttpVersion = version, }; await HeaderParser.ReadHeaders(clientStreamReader, connectRequest.Headers); var connectArgs = new TunnelConnectSessionEventArgs(BufferSize, endPoint, connectRequest, ExceptionFunc); connectArgs.ProxyClient.TcpClient = tcpClient; connectArgs.ProxyClient.ClientStream = clientStream; await endPoint.InvokeTunnectConnectRequest(this, connectArgs, ExceptionFunc); if (await CheckAuthorization(clientStreamWriter, connectArgs) == false) { await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc); return; } //write back successfull CONNECT response var response = ConnectResponse.CreateSuccessfullConnectResponse(version); response.Headers.FixProxyHeaders(); connectArgs.WebSession.Response = response; await clientStreamWriter.WriteResponseAsync(response); var clientHelloInfo = await SslTools.PeekClientHello(clientStream); bool isClientHello = clientHelloInfo != null; if (isClientHello) { connectRequest.ClientHelloInfo = clientHelloInfo; } await endPoint.InvokeTunnectConnectResponse(this, connectArgs, ExceptionFunc, isClientHello); if (!excluded && isClientHello) { connectRequest.RequestUri = new Uri("https://" + httpUrl); SslStream sslStream = null; try { sslStream = new SslStream(clientStream); string certName = HttpHelper.GetWildCardDomainName(connectHostname); var certificate = endPoint.GenericCertificate ?? await CertificateManager.CreateCertificateAsync(certName); //Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SupportedSslProtocols, false); //HTTPS server created - we can now decrypt the client's traffic clientStream = new CustomBufferedStream(sslStream, BufferSize); clientStreamReader.Dispose(); clientStreamReader = new CustomBinaryReader(clientStream, BufferSize); clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize); } catch { sslStream?.Dispose(); return; } if (await HttpHelper.IsConnectMethod(clientStream) == -1) { // It can be for example some Google (Cloude Messaging for Chrome) magic excluded = true; } } //Hostname is excluded or it is not an HTTPS connect if (excluded || !isClientHello) { //create new connection using (var connection = await GetServerConnection(connectArgs, true)) { if (isClientHello) { int available = clientStream.Available; if (available > 0) { //send the buffered data var data = BufferPool.GetBuffer(BufferSize); try { // clientStream.Available sbould be at most BufferSize because it is using the same buffer size await clientStream.ReadAsync(data, 0, available); await connection.StreamWriter.WriteAsync(data, 0, available, true); } finally { BufferPool.ReturnBuffer(data); } } var serverHelloInfo = await SslTools.PeekServerHello(connection.Stream); ((ConnectResponse)connectArgs.WebSession.Response).ServerHelloInfo = serverHelloInfo; } await TcpHelper.SendRaw(clientStream, connection.Stream, BufferSize, (buffer, offset, count) => { connectArgs.OnDataSent(buffer, offset, count); }, (buffer, offset, count) => { connectArgs.OnDataReceived(buffer, offset, count); }, ExceptionFunc); } return; } } //Now create the request await HandleHttpSessionRequest(tcpClient, clientStream, clientStreamReader, clientStreamWriter, connectHostname, endPoint, connectRequest); } catch (ProxyHttpException e) { ExceptionFunc(e); } catch (IOException e) { ExceptionFunc(new Exception("Connection was aborted", e)); } catch (SocketException e) { ExceptionFunc(new Exception("Could not connect", e)); } catch (Exception e) { ExceptionFunc(new Exception("Error occured in whilst handling the client", e)); } finally { clientStreamReader.Dispose(); clientStream.Dispose(); } }
private static void AquireBuffersConcurrently(BufferPool pool, List<IBuffer> bufferList, int threadNumber, int sizeOdd, int sizeEven) { object bufferList_sync = new object(); ManualResetEvent mre = new ManualResetEvent(false); for (int i = 0; i < threadNumber; i++) { Thread thread = new Thread(delegate(object number) { var size = ((int)number % 2 == 1 ? sizeOdd : sizeEven); //wait for signal mre.WaitOne(); //Aquire buffer IBuffer buff = pool.GetBuffer(size); //Add to Queue lock (bufferList_sync) { bufferList.Add(buff); } }); thread.IsBackground = true; thread.Start(i); } Thread.Sleep(500); //ensure all threads are waiting for signal mre.Set(); //signal event //Wait till all threads are done while (true) { lock (bufferList) { if (bufferList.Count == threadNumber) break; Thread.Sleep(500); } } }
/// <summary> /// 保存现在的Buffer到命令Buffer队列 /// 获取一个新的Buffer /// </summary> private void PushCurrentBufferAndGetNewBuffer() { _cmdBuffer.Add(new ArraySegment <byte>(_currentBuffer, 0, _currentBufferIndex)); _currentBuffer = BufferPool.GetBuffer(); _currentBufferIndex = 0; }