/// <summary> /// Runs two instances of RunAsyncInternal in parallel. /// </summary> /// <returns>true if the test passes, false otherwise.</returns> public override async Task <bool> RunAsync() { log.Trace("()"); ClientCallee = new ProtocolClient(); CalleeWriteLock = new SemaphoreSlim(1); CalleeCounter = new UnfinishedRequestCounter() { Name = string.Format("Callee") }; Task <bool>[] tasks = new Task <bool> [ClientPairCount]; for (int i = 0; i < ClientPairCount; i++) { tasks[i] = RunAsyncInternal(i); } bool res = true; for (int i = 0; i < ClientPairCount; i++) { if (!await tasks[i]) { res = false; } } Passed = true; for (int i = 0; i < ClientPairCount; i++) { if (!PassedArray[i]) { Passed = false; break; } } ClientCallee.Dispose(); log.Trace("(-):{0}", res); return(res); }
/// <summary> /// Receives messages from the open relay and sends confirmations for the incoming messages back to the profile server. /// </summary> /// <param name="Client">Client connected to clAppService port with an initialized relay.</param> /// <param name="Builder">Client's message builder.</param> /// <param name="Name">Log prefix.</param> /// <param name="WriteLock">Lock object to protect write access to client's stream.</param> /// <param name="UnfinishedRequestCounter">Unfinished request counter object.</param> /// <returns></returns> public static async Task <byte[]> MessageReceivingLoop(ProtocolClient Client, MessageBuilder Builder, string Name, SemaphoreSlim WriteLock, UnfinishedRequestCounter UnfinishedRequestCounter) { string prefix = string.Format("[{0}] ", Name); log.Trace(prefix + "()"); List <byte[]> chunksReceived = new List <byte[]>(); int totalSize = 0; int ackReceived = 0; while ((chunksReceived.Count < DataMessageCountPerClient) || (ackReceived < DataMessageCountPerClient)) { Message incomingMessage = await Client.ReceiveMessageAsync(); if (incomingMessage.MessageTypeCase == Message.MessageTypeOneofCase.Request) { // We have received message from the other client. if ((incomingMessage.Request.ConversationTypeCase == Request.ConversationTypeOneofCase.SingleRequest) && (incomingMessage.Request.SingleRequest.RequestTypeCase == SingleRequest.RequestTypeOneofCase.ApplicationServiceReceiveMessageNotification)) { byte[] receivedData = incomingMessage.Request.SingleRequest.ApplicationServiceReceiveMessageNotification.Message.ToByteArray(); chunksReceived.Add(receivedData); log.Trace(prefix + "Received data message #{0} - {1} bytes.", chunksReceived.Count, receivedData.Length); totalSize += receivedData.Length; // Sending ACK back to the profile server. await WriteLock.WaitAsync(); Message ackResponse = Builder.CreateApplicationServiceReceiveMessageNotificationResponse(incomingMessage); await Client.SendMessageAsync(ackResponse); WriteLock.Release(); } else { log.Trace(prefix + "Received invalid message, terminating loop."); break; } } else { // We have received confirmation of our message being delivered. if ((incomingMessage.Response.ConversationTypeCase == Response.ConversationTypeOneofCase.SingleResponse) && (incomingMessage.Response.SingleResponse.ResponseTypeCase == SingleResponse.ResponseTypeOneofCase.ApplicationServiceSendMessage)) { ackReceived++; UnfinishedRequestCounter.Decrement(); log.Trace(prefix + "Received ACK to message ID {0}, ack count {1}.", incomingMessage.Id, ackReceived); } else { log.Trace(prefix + "Received invalid message, terminating loop."); break; } } } // Count final hash. int offset = 0; byte[] data = new byte[totalSize]; foreach (byte[] chunk in chunksReceived) { Array.Copy(chunk, 0, data, offset, chunk.Length); offset += chunk.Length; } byte[] finalHash = Crypto.Sha256(data); log.Trace(prefix + "(-):{0}", Crypto.ToHex(finalHash)); return(finalHash); }
/// <summary> /// Sends data messages to the other client. /// </summary> /// <param name="Client">Client connected to clAppService port with an initialized relay.</param> /// <param name="Builder">Client's message builder.</param> /// <param name="Name">Log prefix.</param> /// <param name="Token">Client's open relay token.</param> /// <param name="WriteLock">Lock object to protect write access to client's stream.</param> /// <param name="UnfinishedRequestCounter">Unfinished request counter object.</param> /// <returns></returns> public static async Task <byte[]> MessageSendingLoop(ProtocolClient Client, MessageBuilder Builder, string Name, byte[] Token, SemaphoreSlim WriteLock, UnfinishedRequestCounter UnfinishedRequestCounter) { string prefix = string.Format("[{0}] ", Name); log.Trace(prefix + "()"); List <byte[]> chunks = new List <byte[]>(); int totalSize = 0; for (int i = 0; i < DataMessageCountPerClient; i++) { // Generate message data. int dataLength = rng.Next(DataMessageSizeMin, DataMessageSizeMax); byte[] msg = new byte[dataLength]; Crypto.Rng.GetBytes(msg); totalSize += dataLength; chunks.Add(msg); // Send message. await UnfinishedRequestCounter.WaitAndIncrement(); await WriteLock.WaitAsync(); Message appServiceMessageRequest = Builder.CreateApplicationServiceSendMessageRequest(Token, msg); await Client.SendMessageAsync(appServiceMessageRequest); WriteLock.Release(); int delay = rng.Next(DataMessageDelayMaxMs); if (delay != 0) { await Task.Delay(delay); } } // Count final hash. int offset = 0; byte[] data = new byte[totalSize]; foreach (byte[] chunk in chunks) { Array.Copy(chunk, 0, data, offset, chunk.Length); offset += chunk.Length; } byte[] finalHash = Crypto.Sha256(data); log.Trace(prefix + "(-):{0}", Crypto.ToHex(finalHash)); return(finalHash); }
/// <summary> /// Implementation of the test itself. /// </summary> /// <returns>true if the test passes, false otherwise.</returns> public async Task <bool> RunAsyncInternal(int Index) { IPAddress ServerIp = (IPAddress)ArgumentValues["Server IP"]; int PrimaryPort = (int)ArgumentValues["primary Port"]; log.Trace("(ServerIp:'{0}',PrimaryPort:{1},Index:{2})", ServerIp, PrimaryPort, Index); bool res = false; PassedArray[Index] = false; ProtocolClient clientCallee = new ProtocolClient(); ProtocolClient clientCalleeAppService = new ProtocolClient(0, SemVer.V100, clientCallee.GetIdentityKeys()); ProtocolClient clientCaller = new ProtocolClient(); ProtocolClient clientCallerAppService = new ProtocolClient(0, SemVer.V100, clientCaller.GetIdentityKeys()); try { MessageBuilder mbCallee = clientCallee.MessageBuilder; MessageBuilder mbCalleeAppService = clientCalleeAppService.MessageBuilder; MessageBuilder mbCaller = clientCaller.MessageBuilder; MessageBuilder mbCallerAppService = clientCallerAppService.MessageBuilder; // Step 1 log.Trace("Step 1"); // Get port list. byte[] pubKeyCallee = clientCallee.GetIdentityKeys().PublicKey; byte[] identityIdCallee = clientCallee.GetIdentityId(); byte[] pubKeyCaller = clientCaller.GetIdentityKeys().PublicKey; byte[] identityIdCaller = clientCaller.GetIdentityId(); await clientCallee.ConnectAsync(ServerIp, PrimaryPort, false); Dictionary <ServerRoleType, uint> rolePorts = new Dictionary <ServerRoleType, uint>(); bool listPortsOk = await clientCallee.ListServerPorts(rolePorts); clientCallee.CloseConnection(); // Establish hosting agreement for identity 1. await clientCallee.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClNonCustomer], true); bool establishHostingOk = await clientCallee.EstablishHostingAsync(); clientCallee.CloseConnection(); // Check-in and initialize the profile of identity 1. await clientCallee.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClCustomer], true); bool checkInOk = await clientCallee.CheckInAsync(); bool initializeProfileOk = await clientCallee.InitializeProfileAsync("Test Identity", null, new GpsLocation(0, 0), null); // Add application service to the current session. string serviceName = "Test Service"; bool addAppServiceOk = await clientCallee.AddApplicationServicesAsync(new List <string>() { serviceName }); // Step 1 Acceptance bool step1Ok = listPortsOk && establishHostingOk && checkInOk && initializeProfileOk && addAppServiceOk; log.Trace("Step 1: {0}", step1Ok ? "PASSED" : "FAILED"); // Step 2 log.Trace("Step 2"); await clientCaller.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClNonCustomer], true); bool verifyIdentityOk = await clientCaller.VerifyIdentityAsync(); Message requestMessage = mbCaller.CreateCallIdentityApplicationServiceRequest(identityIdCallee, serviceName); await clientCaller.SendMessageAsync(requestMessage); // Step 2 Acceptance bool step2Ok = verifyIdentityOk; log.Trace("Step 2: {0}", step2Ok ? "PASSED" : "FAILED"); // Step 3 log.Trace("Step 3"); Message serverRequestMessage = await clientCallee.ReceiveMessageAsync(); byte[] receivedPubKey = serverRequestMessage.Request.ConversationRequest.IncomingCallNotification.CallerPublicKey.ToByteArray(); bool pubKeyOk = StructuralComparisons.StructuralComparer.Compare(receivedPubKey, pubKeyCaller) == 0; bool serviceNameOk = serverRequestMessage.Request.ConversationRequest.IncomingCallNotification.ServiceName == serviceName; bool incomingCallNotificationOk = pubKeyOk && serviceNameOk; byte[] calleeToken = serverRequestMessage.Request.ConversationRequest.IncomingCallNotification.CalleeToken.ToByteArray(); Message serverResponseMessage = mbCallee.CreateIncomingCallNotificationResponse(serverRequestMessage); await clientCallee.SendMessageAsync(serverResponseMessage); // Connect to clAppService and send initialization message. await clientCalleeAppService.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClAppService], true); Message requestMessageAppServiceCallee = mbCalleeAppService.CreateApplicationServiceSendMessageRequest(calleeToken, null); await clientCalleeAppService.SendMessageAsync(requestMessageAppServiceCallee); // Step 3 Acceptance bool step3Ok = incomingCallNotificationOk; log.Trace("Step 3: {0}", step3Ok ? "PASSED" : "FAILED"); // Step 4 log.Trace("Step 4"); Message responseMessage = await clientCaller.ReceiveMessageAsync(); bool idOk = responseMessage.Id == requestMessage.Id; bool statusOk = responseMessage.Response.Status == Status.Ok; byte[] callerToken = responseMessage.Response.ConversationResponse.CallIdentityApplicationService.CallerToken.ToByteArray(); bool callIdentityOk = idOk && statusOk; // Connect to clAppService and send initialization message. await clientCallerAppService.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClAppService], true); Message requestMessageAppServiceCaller = mbCallerAppService.CreateApplicationServiceSendMessageRequest(callerToken, null); await clientCallerAppService.SendMessageAsync(requestMessageAppServiceCaller); Message responseMessageAppServiceCaller = await clientCallerAppService.ReceiveMessageAsync(); idOk = responseMessageAppServiceCaller.Id == requestMessageAppServiceCaller.Id; statusOk = responseMessageAppServiceCaller.Response.Status == Status.Ok; bool initAppServiceMessageOk = idOk && statusOk; // And close connection to clNonCustomer port. clientCaller.CloseConnection(); // Step 4 Acceptance bool step4Ok = callIdentityOk && initAppServiceMessageOk; log.Trace("Step 4: {0}", step4Ok ? "PASSED" : "FAILED"); // Step 5 log.Trace("Step 5"); Message responseMessageAppServiceCallee = await clientCalleeAppService.ReceiveMessageAsync(); idOk = responseMessageAppServiceCallee.Id == requestMessageAppServiceCallee.Id; statusOk = responseMessageAppServiceCallee.Response.Status == Status.Ok; bool typeOk = (responseMessageAppServiceCallee.MessageTypeCase == Message.MessageTypeOneofCase.Response) && (responseMessageAppServiceCallee.Response.ConversationTypeCase == Response.ConversationTypeOneofCase.SingleResponse) && (responseMessageAppServiceCallee.Response.SingleResponse.ResponseTypeCase == SingleResponse.ResponseTypeOneofCase.ApplicationServiceSendMessage); bool appServiceSendOk = idOk && statusOk && typeOk; // Step 5 Acceptance bool step5Ok = appServiceSendOk; log.Trace("Step 5: {0}", step5Ok ? "PASSED" : "FAILED"); // Step 6 UnfinishedRequestCounter callerCounter = new UnfinishedRequestCounter() { Name = string.Format("Caller-{0}", Index) }; UnfinishedRequestCounter calleeCounter = new UnfinishedRequestCounter() { Name = string.Format("Callee-{0}", Index) }; SemaphoreSlim callerWriteLock = new SemaphoreSlim(1); SemaphoreSlim calleeWriteLock = new SemaphoreSlim(1); Task <byte[]> messageReceivingTaskCaller = MessageReceivingLoop(clientCallerAppService, mbCallerAppService, "CallerReceiving", callerWriteLock, callerCounter); Task <byte[]> messageReceivingTaskCallee = MessageReceivingLoop(clientCalleeAppService, mbCalleeAppService, "CalleeReceiving", calleeWriteLock, calleeCounter); Task <byte[]> messageSendingTaskCaller = MessageSendingLoop(clientCallerAppService, mbCallerAppService, "CallerSending", callerToken, callerWriteLock, callerCounter); Task <byte[]> messageSendingTaskCallee = MessageSendingLoop(clientCalleeAppService, mbCalleeAppService, "CalleeSending", calleeToken, calleeWriteLock, calleeCounter); byte[] callerSendMessageHash = messageSendingTaskCaller.Result; byte[] calleeSendMessageHash = messageSendingTaskCallee.Result; byte[] callerReceiveMessageHash = messageReceivingTaskCaller.Result; byte[] calleeReceiveMessageHash = messageReceivingTaskCallee.Result; bool callerMessageHashOk = StructuralComparisons.StructuralComparer.Compare(callerSendMessageHash, calleeReceiveMessageHash) == 0; bool calleeMessageHashOk = StructuralComparisons.StructuralComparer.Compare(calleeSendMessageHash, callerReceiveMessageHash) == 0; // Step 6 Acceptance bool step6Ok = callerMessageHashOk && calleeMessageHashOk; log.Trace("Step 6: {0}", step6Ok ? "PASSED" : "FAILED"); PassedArray[Index] = step1Ok && step2Ok && step3Ok && step4Ok && step5Ok && step6Ok; log.Trace("PassedArray[{0}] = {1}", Index, PassedArray[Index]); res = true; } catch (Exception e) { log.Error("Exception occurred: {0}", e.ToString()); } clientCallee.Dispose(); clientCalleeAppService.Dispose(); clientCaller.Dispose(); clientCallerAppService.Dispose(); log.Trace("(-):{0}", res); return(res); }