private static async Task ProfileServiceOperationAsync(Func <IUserCredentials, ILogger, IUserProfileServiceResult> operation, string name, IUserProfileNamedPipeFactory pipeFactory, int serverTimeOutms = 0, int clientTimeOutms = 0, CancellationToken ct = default(CancellationToken), ILogger logger = null) { using (NamedPipeServerStream server = pipeFactory.CreatePipe(name)) { await server.WaitForConnectionAsync(ct); ManualResetEventSlim forceDisconnect = new ManualResetEventSlim(false); try { if (serverTimeOutms + clientTimeOutms > 0) { Task.Run(() => { // This handles Empty string input cases. This is usually the case were client is connected and writes a empty string. // on the server side this blocks the ReadAsync indefinitely (even with the cancellation set). The code below protects // the server from being indefinitely blocked by a malicious client. forceDisconnect.Wait(serverTimeOutms + clientTimeOutms); if (server.IsConnected) { server.Disconnect(); logger?.LogError(Resources.Error_ClientTimedOut); } }).DoNotWait(); } using (var cts = CancellationTokenSource.CreateLinkedTokenSource(ct)) { if (serverTimeOutms > 0) { cts.CancelAfter(serverTimeOutms); } byte[] requestRaw = new byte[1024]; int bytesRead = 0; while (bytesRead == 0 && !cts.IsCancellationRequested) { bytesRead = await server.ReadAsync(requestRaw, 0, requestRaw.Length, cts.Token); } string json = Encoding.Unicode.GetString(requestRaw, 0, bytesRead); var requestData = Json.DeserializeObject <RUserProfileServiceRequest>(json); var result = operation?.Invoke(requestData, logger); string jsonResp = JsonConvert.SerializeObject(result); byte[] respData = Encoding.Unicode.GetBytes(jsonResp); await server.WriteAsync(respData, 0, respData.Length, cts.Token); await server.FlushAsync(cts.Token); } using (var cts = CancellationTokenSource.CreateLinkedTokenSource(ct)) { if (clientTimeOutms > 0) { cts.CancelAfter(clientTimeOutms); } // Waiting here to allow client to finish reading client should disconnect after reading. byte[] requestRaw = new byte[1024]; int bytesRead = 0; while (bytesRead == 0 && !cts.Token.IsCancellationRequested) { bytesRead = await server.ReadAsync(requestRaw, 0, requestRaw.Length, cts.Token); } // if there was an attempt to write, disconnect. server.Disconnect(); } } finally { // server work is done. forceDisconnect.Set(); } } }
private async Task CreateProfileFuzzTestRunnerAsync(IUserProfileServices creator, IUserProfileNamedPipeFactory pipeFactory, string input, int serverTimeOut, int clientTimeOut) { var task = Task.Run(async() => { try { await RUserProfileServicesHelper.CreateProfileAsync(serverTimeOutms: serverTimeOut, clientTimeOutms: clientTimeOut, userProfileService: creator, pipeFactory: pipeFactory); } catch (JsonReaderException) { // expecting JSON parsing to fail // JSON parsing may fail due to randomly generated strings as input. } }); using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(clientTimeOut))) { var result = await CreateProfileClientTestWorkerAsync(input, cts.Token); // fuzz test parsing succeeded, the creator always fails for this test. result?.Error.Should().Be(13); } await ParallelTools.When(task, serverTimeOut + clientTimeOut); }
public static async Task DeleteProfileAsync(int serverTimeOutms = 0, int clientTimeOutms = 0, IUserProfileServices userProfileService = null, IUserProfileNamedPipeFactory pipeFactory = null, CancellationToken ct = default(CancellationToken), ILogger logger = null) { userProfileService = userProfileService ?? new RUserProfileServices(); pipeFactory = pipeFactory ?? new NamedPipeServerStreamFactory(); await ProfileServiceOperationAsync(userProfileService.DeleteUserProfile, NamedPipeServerStreamFactory.DeletorName, pipeFactory, serverTimeOutms, clientTimeOutms, ct, logger); }
private async Task CreateProfileTestRunnerAsync(IUserProfileServices creator, IUserProfileNamedPipeFactory pipeFactory, string input, bool isValidParse, bool isValidAccount, bool isExistingAccount, int serverTimeOut, int clientTimeOut) { var testDone = new ManualResetEventSlim(false); Task.Run(async() => { try { if (isValidParse) { Func <Task> f = async() => await RUserProfileServicesHelper.CreateProfileAsync(serverTimeOutms: serverTimeOut, clientTimeOutms: clientTimeOut, userProfileService: creator, pipeFactory: pipeFactory); f.ShouldNotThrow(); } else { Func <Task> f = () => RUserProfileServicesHelper.CreateProfileAsync(serverTimeOutms: serverTimeOut, clientTimeOutms: clientTimeOut, userProfileService: creator, pipeFactory: pipeFactory); await f.ShouldThrowAsync <Exception>(); } } finally { testDone.Set(); } }).DoNotWait(); using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(clientTimeOut))) { var result = await CreateProfileClientTestWorkerAsync(input, cts.Token); if (isValidParse) { result.Error.Should().Be((uint)(isValidAccount ? 0 : 13)); result.ProfileExists.Should().Be(isExistingAccount); } else { result.Should().BeNull(); } } testDone.Wait(serverTimeOut + clientTimeOut); }