/// <summary> /// Redirect recived query from current server to other. /// </summary> /// <param name="tc">Server's transmission controller.</param> /// <param name="query">Query received from client.</param> public static void QueryHandler_DuplexRelay(BaseServerTransmissionController tc, UniformQueries.Query query) { bool decryptionComplete = false; bool decryptionResult = false; Task decryptionOperation = new Task(async delegate() { // Try to encrypt receved message. decryptionResult = await EnctyptionOperatorsHandler.TryToDecryptAsync( query, EnctyptionOperatorsHandler.AsymmetricEO); decryptionComplete = true; }); decryptionOperation.Start(); // Whait for decription completing. while (!decryptionComplete) { Thread.Sleep(5); } // Loging error to client. if (!decryptionResult) { // Try to get answer in string format. SendAnswerViaPP("DUPLEX RELEAY ERROR: Data corrupted." + " Decryption not possible. Relay terminated.", query); return; } // Detect routing target. bool relayTargetFound = UniformClient.BaseClient.routingTable. TryGetRoutingInstruction(query, out Instruction instruction); // If instruction not found. if (!relayTargetFound) { // If reley target not found then server will mean that query requested to itself. PipesProvider.Handlers.Queries.ProcessingAsync(tc, query); //// Log //Console.WriteLine("RELAY TARGET NOT FOUND: {q}", query); //// DO BACKWARED ERROR INFORMATION. //SendAnswer("error=404", UniformQueries.API.DetectQueryParts(query)); // Drop continue computing. return; } // Open connection. TransmissionLine tl = UniformClient.BaseClient.EnqueueDuplexQueryViaPP( instruction.routingIP, instruction.pipeName, query, // Delegate that will invoked when relayed server send answer. // Redirects the answer to a client. delegate(TransmissionLine answerTL, UniformQueries.Query receivedData) { // Try to get answer in string format. SendAnswerViaPP(receivedData, query); return; }); }
/// <summary> /// Validates and fixed a configuration and params of the transmission line. /// </summary> /// <param name="line">A transmission line for configuration.</param> /// <returns>A result of configurating. False if failed.</returns> public static async Task <bool> ConfigurateTransmissionLineAsync(TransmissionLine line) { if (line.RoutingInstruction != null) // Routing instruction applied. { // Is partial autorized instruction. if (line.RoutingInstruction is PartialAuthorizedInstruction pai) { #region Token validation // If token not exist, or emoty, or expired. if (line.LastQuery.Data.TryGetParamValue("token", out UniformQueries.QueryPart token)) { // If token value is emoty. if (string.IsNullOrEmpty(token.PropertyValueString)) { if (await TokenValidation(pai)) { // Apply received token. line.LastQuery.Data.SetParam(new UniformQueries.QueryPart("token", pai.GuestToken)); } else { return(false); } } } else { // Validate token if (await TokenValidation(pai)) { // Add tokent to query, line.LastQuery.Data.ListedContent?.Add(new UniformQueries.QueryPart("token", pai.GuestToken)); } else { return(false); } } #region Methods // Trying to porovide valid guest token. // Returns result of validation. False - token invalid. async Task <bool> TokenValidation(PartialAuthorizedInstruction instruction) { // If guest token is not found or expired. if (pai.GuestToken == null || UniformQueries.Tokens.IsExpired(instruction.GuestToken, instruction.GuestTokenHandler.ExpiryTime)) { // Wait for token. if (!await pai.TryToGetGuestTokenAsync(ClientAppConfigurator.TerminationTokenSource.Token)) { return(false); } } return(true); } #endregion #endregion #region Encriprion operators validation if (line.LastQuery.Data.IsEncrypted && // Is query require encryption? (Query can't be encrypted if that query must request key for encryption.) line.RoutingInstruction != null && // Is routing instruction is valid and allow encryption? line.RoutingInstruction.encryption) { // Check asymmetric operator. if (pai.AsymmetricEncryptionOperator == null) { Console.WriteLine("Encryption operator not configurated. Operation declined."); return(false); } #region Receiving public key from intruction's target server // Check if operator is valid. if (!pai.AsymmetricEncryptionOperator.IsValid) { try { // Start async key exchanging. var keysExchangingOperator = RequestPublicEncryptionKeyAsync(pai); try { if (!keysExchangingOperator.IsCompleted) { keysExchangingOperator.Start(); } } catch { }; // Drop current query as invalid cause encryption operator still in processing. line.Processing = false; return(false); } catch (Exception ex) { // Unlock loop. line.Processing = false; Console.WriteLine("SECRET KEY ERROR (bcpph1): " + ex.Message); return(false); } } #endregion #region Adding public key for backward encryption if not added yet if (!line.LastQuery.Data.QueryParamExist("pk")) { line.LastQuery.Data.SetParam(new UniformQueries.QueryPart( "pk", EnctyptionOperatorsHandler.AsymmetricEO.EncryptionKey)); } #endregion // Encrypt query by public key of target server. return(await EnctyptionOperatorsHandler.TryToEncryptAsync( line.LastQuery.Data, line.RoutingInstruction.sEncCode, line.RoutingInstruction.AsymmetricEncryptionOperator, ClientAppConfigurator.TerminationTokenSource.Token)); } #endregion } } return(true); }
/// <summary> /// A handler that will recives a message from a server. /// </summary> /// <param name="sharedObject"> /// Normaly is a <see cref="TransmissionLine"/> that contains information about current transmission. /// </param> public static async void HandlerInputTransmissionAsync(object sharedObject) { // Drop as invalid in case of incorrect transmitted data. if (!(sharedObject is TransmissionLine lineProcessor)) { Console.WriteLine("TRANSMISSION ERROR (UQPP0): INCORRECT TRANSFERD DATA TYPE. PERMITED ONLY \"LineProcessor\""); return; } // Mark line as busy to avoid calling of next query, cause this handler is async. lineProcessor.Processing = true; #region Reciving message // Open stream reader. byte[] receivedData = null; try { Console.WriteLine("{0}/{1}: WAITING FOR MESSAGE", lineProcessor.ServerName, lineProcessor.ServerPipeName); // Avoid an error caused to disconection of client. try { receivedData = await UniformDataOperator.Binary.IO.StreamHandler.StreamReaderAsync(lineProcessor.pipeClient); } // Catch the Exception that is raised if the pipe is broken or disconnected. catch (Exception e) { // Log error. Console.WriteLine("DNS HANDLER ERROR (USAH0): {0}", e.Message); // Stop processing merker to pass async block. lineProcessor.Processing = false; // Close processor case this line already deprecated on the server side as single time task. lineProcessor.Close(); return; } } // Catch the Exception that is raised if the pipe is broken or disconnected. catch (Exception e) { // Log if (receivedData == null || receivedData.Length == 0) { Console.WriteLine("DNS HANDLER ERROR ({1}): {0}", e.Message, lineProcessor.pipeClient.GetHashCode()); } } #endregion // Log if (receivedData == null || receivedData.Length == 0) { Console.WriteLine("{0}/{1}: RECEIVED MESSAGE IS EMPTY.", lineProcessor.ServerName, lineProcessor.ServerPipeName); } else { // Log state. Console.WriteLine("{0}/{1}: MESSAGE RECIVED", lineProcessor.ServerName, lineProcessor.ServerPipeName); // Decode to Query. UniformQueries.Query receviedQuery; try { receviedQuery = UniformDataOperator.Binary.BinaryHandler.FromByteArray <UniformQueries.Query>(receivedData); } catch (Exception ex) { Console.WriteLine("DNS HANDLER ERROR 401({1}): QUERY DAMAGED : {0}", ex.Message, lineProcessor.pipeClient.GetHashCode()); // Stop processing merker to pass async block. lineProcessor.Processing = false; // Close processor case this line already deprecated on the server side as single time task. lineProcessor.Close(); return; } // Decrypt if required. await EnctyptionOperatorsHandler.TryToDecryptAsync( receviedQuery, EnctyptionOperatorsHandler.AsymmetricEO, ClientAppConfigurator.TerminationTokenSource.Token); #region Processing message // Try to call answer handler. string tableGUID = lineProcessor.ServerName + "\\" + lineProcessor.ServerPipeName; // Look for delegate in table. if (DuplexBackwardCallbacks[tableGUID] is Action <TransmissionLine, UniformQueries.Query> registredCallback) { if (registredCallback != null) { // Invoke delegate if found and has dubscribers. registredCallback.Invoke(lineProcessor, receviedQuery); // Drop reference. DuplexBackwardCallbacks.Remove(tableGUID); // Inform subscribers about answer receiving. eDuplexBackwardCallbacksReceived?.Invoke(tableGUID); } else { Console.WriteLine("{0}/{1}: ANSWER CALLBACK HAS NO SUBSCRIBERS", lineProcessor.ServerName, lineProcessor.ServerPipeName); } } else { Console.WriteLine("{0}/{1}: ANSWER HANDLER NOT FOUND BY {2}", lineProcessor.ServerName, lineProcessor.ServerPipeName, tableGUID); } //Console.WriteLine("{0}/{1}: ANSWER READING FINISH.\nMESSAGE: {2}", // lineProcessor.ServerName, lineProcessor.ServerPipeName, message); #endregion } // Stop processing merker to pass async block. lineProcessor.Processing = false; // Close processor case this line already deprecated on the server side as single time task. lineProcessor.Close(); }
/// <summary> /// Code that will work on server loop when connection will be established. /// Recoomended to using as default DNS Handler for queries reciving. /// </summary> public static async void ClientToServerAsync(BaseServerTransmissionController controller) { DateTime sessionTime = DateTime.Now.AddSeconds(5000); // Read until trasmition exits not finished. while (controller.PipeServer.IsConnected) { // Open stream reader. byte[] binaryQuery; #region Reciving message // Read data from stream. // Avoid an error caused to disconection of client. try { binaryQuery = await StreamHandler.StreamReaderAsync(controller.PipeServer); } // Catch the Exception that is raised if the pipe is broken or disconnected. catch (Exception e) { Console.WriteLine("DNS HANDLER ERROR: {0}", e.Message); return; } if (DateTime.Compare(sessionTime, DateTime.Now) < 0) { Console.WriteLine("Connection terminated cause allowed time has expired."); // Avoid disconnectin error. try { controller.PipeServer.Disconnect(); } catch { // Exception caused by disconecction on client side. } return; } #endregion #region Finalizing connection // Disconnect user if query recived. if (controller.PipeServer.IsConnected) { try { controller.PipeServer.Disconnect(); } catch { // Exception caused by disconecction on client side. } } // Remove temporal data. controller.PipeServer.Dispose(); #endregion #region Query processing // Drop if stream is over. if (binaryQuery == null || binaryQuery.Length == 0) { //Console.WriteLine("NULL REQUEST AVOIDED. CONNECTION TERMINATED."); break; } // Decode query from binary data. Query query; try { query = UniformDataOperator.Binary.BinaryHandler.FromByteArray <Query>(binaryQuery); } catch (Exception ex) { Console.WriteLine("DNS HANDLER ERROR (DNS50): DAMAGED DATA : {0}", ex.Message); return; } // Try to decrypt. In case of fail decryptor returns an entry message. await EnctyptionOperatorsHandler.TryToDecryptAsync( query, EnctyptionOperatorsHandler.AsymmetricEO); // Log query. Console.WriteLine(@"RECIVED QUERY (DNS0): {0}", query); // Try to get correct transmisssion controller. if (controller is ClientToServerTransmissionController CToSTS) { // Redirect handler. CToSTS.queryHandlerCallback?.Invoke(controller, query); } else { // Log error. Console.WriteLine(@"DNS HANDLER ERROR (DNS40):\nQuery processing not posssible.\nTransmission controller not {0}", typeof(ClientToServerTransmissionController).FullName); } #endregion } // Log about transmission finish. Console.WriteLine("{0} : TRANSMISSION FINISHED AT {1}", controller.PipeName, DateTime.Now.ToString("HH:mm:ss.fff")); }