private void ProcessSync(ZkSession session, BinaryReader binReader, BinaryWriter binWriter, Stopwatch sw) { var syncCat = "Sync"; string serviceTypeName; if (_requireZk) { //use session and encryption - if throws should not have gotten this far var len = binReader.ReadInt32(); var bytes = binReader.ReadBytes(len); var data = session.Crypto.Decrypt(bytes); serviceTypeName = data.ConverToString(); } else { serviceTypeName = binReader.ReadString(); } int serviceKey; if (_serviceKeys.TryGetValue(serviceTypeName, out serviceKey)) { ServiceInstance instance; if (_services.TryGetValue(serviceKey, out instance)) { syncCat = instance.InterfaceType.Name; //Create a list of sync infos from the dictionary var syncBytes = _serializer.Serialize(instance.ServiceSyncInfo); if (_requireZk) { _log.Debug("Unencrypted data sent to server: {0}", Convert.ToBase64String(syncBytes)); var encData = session.Crypto.Encrypt(syncBytes); binWriter.Write(encData.Length); binWriter.Write(encData); _log.Debug("Encrypted data sent server: {0}", Convert.ToBase64String(encData)); } else { binWriter.Write(syncBytes.Length); binWriter.Write(syncBytes); } } } else { //return zero to indicate type or version of type not found binWriter.Write(0); } binWriter.Flush(); _log.Debug("SyncInterface for {0} in {1}ms.", syncCat, sw.ElapsedMilliseconds); }
private void ProcessInvocation(ZkSession session, BinaryReader binReader, BinaryWriter binWriter, Stopwatch sw) { //read service instance key var cat = "unknown"; var stat = "MethodInvocation"; int invokedServiceKey = binReader.ReadInt32(); ServiceInstance invokedInstance; if (_services.TryGetValue(invokedServiceKey, out invokedInstance)) { cat = invokedInstance.InterfaceType.Name; //read the method identifier int methodHashCode = binReader.ReadInt32(); if (invokedInstance.InterfaceMethods.ContainsKey(methodHashCode)) { MethodInfo method; invokedInstance.InterfaceMethods.TryGetValue(methodHashCode, out method); stat = method.Name; bool[] isByRef; invokedInstance.MethodParametersByRef.TryGetValue(methodHashCode, out isByRef); //read parameter data object[] parameters; if (_requireZk) { var len = binReader.ReadInt32(); var encData = binReader.ReadBytes(len); _log.Debug("Encrypted data received from server: {0}", Convert.ToBase64String(encData)); var data = session.Crypto.Decrypt(encData); _log.Debug("Decrypted data received from server: {0}", Convert.ToBase64String(data)); using (var ms = new MemoryStream(data)) using (var br = new BinaryReader(ms)) { parameters = _parameterTransferHelper.ReceiveParameters(br); } } else { parameters = _parameterTransferHelper.ReceiveParameters(binReader); } //invoke the method object[] returnParameters; var returnMessageType = MessageType.ReturnValues; try { object returnValue = method.Invoke(invokedInstance.SingletonInstance, parameters); if (returnValue is Task task) { task.GetAwaiter().GetResult(); var prop = task.GetType().GetProperty("Result"); returnValue = prop?.GetValue(task); } //the result to the client is the return value (null if void) and the input parameters returnParameters = new object[1 + parameters.Length]; returnParameters[0] = returnValue; for (int i = 0; i < parameters.Length; i++) { returnParameters[i + 1] = isByRef[i] ? parameters[i] : null; } } catch (Exception ex) { //an exception was caught. Rethrow it client side returnParameters = new object[] { ex }; returnMessageType = MessageType.ThrowException; } //send the result back to the client // (1) write the message type binWriter.Write((int)returnMessageType); // (2) write the return parameters if (_requireZk) { byte[] data; using (var ms = new MemoryStream()) using (var bw = new BinaryWriter(ms)) { _parameterTransferHelper.SendParameters( invokedInstance.ServiceSyncInfo.UseCompression, invokedInstance.ServiceSyncInfo.CompressionThreshold, bw, returnParameters); data = ms.ToArray(); } _log.Debug("Unencrypted data sent server: {0}", Convert.ToBase64String(data)); var encData = session.Crypto.Encrypt(data); _log.Debug("Encrypted data sent server: {0}", Convert.ToBase64String(encData)); binWriter.Write(encData.Length); binWriter.Write(encData); } else { _parameterTransferHelper.SendParameters( invokedInstance.ServiceSyncInfo.UseCompression, invokedInstance.ServiceSyncInfo.CompressionThreshold, binWriter, returnParameters); } } else { binWriter.Write((int)MessageType.UnknownMethod); } } else { binWriter.Write((int)MessageType.UnknownMethod); } //flush binWriter.Flush(); _stats.Log(cat, stat, sw.ElapsedMilliseconds); }
/// <summary> /// This method handles all requests from a single client. /// There is one thread running this method for each connected client. /// </summary> /// <param name="readStream">The read/write stream.</param> /// <param name="writeStream">The read/write stream.</param> protected virtual void ProcessRequest(Stream readStream, Stream writeStream) { if (null == readStream || null == writeStream) { return; } var binReader = new BinaryReader(readStream); var binWriter = new BinaryWriter(writeStream); bool doContinue = true; try { ZkSession zkSession = null; do { var sw = Stopwatch.StartNew(); try { //read message type var messageType = (MessageType)binReader.ReadInt32(); switch (messageType) { case MessageType.ZkInitiate: zkSession = new ZkSession(_zkRepository, _log, _stats); doContinue = zkSession.ProcessZkInitiation(binReader, binWriter, sw); break; case MessageType.ZkProof: if (null == zkSession) { throw new NullReferenceException("session null"); } doContinue = zkSession.ProcessZkProof(binReader, binWriter, sw); break; case MessageType.SyncInterface: ProcessSync(zkSession, binReader, binWriter, sw); break; case MessageType.MethodInvocation: ProcessInvocation(zkSession, binReader, binWriter, sw); break; case MessageType.TerminateConnection: doContinue = false; break; default: doContinue = false; break; } } catch (Exception e) //do not resume operation on this thread if any errors are unhandled. { _log.Error("Error in ProcessRequest: {0}", e.ToString().Flatten()); doContinue = false; } sw.Stop(); }while (doContinue); } catch (Exception fatalException) { _log.Fatal("Fatal error in ProcessRequest: {0}", fatalException.ToString().Flatten()); } finally { binReader.Close(); binWriter.Close(); } }