internal SerializedDataStream(int fragmentSize) { SerializedDataStream._trace.WriteLine("Creating SerializedDataStream with fragmentsize : {0}", (object)fragmentSize); this.syncObject = new object(); this.currentFragment = new FragmentedRemoteObject(); this.queuedStreams = new Queue <MemoryStream>(); this.fragmentSize = fragmentSize; }
/// <summary> /// Creates a stream to hold serialized data. /// </summary> /// <param name="fragmentSize"> /// fragmentSize to be used while creating fragment boundaries. /// </param> internal SerializedDataStream(int fragmentSize) { s_trace.WriteLine("Creating SerializedDataStream with fragmentsize : {0}", fragmentSize); Dbg.Assert(fragmentSize > 0, "fragmentsize should be greater than 0."); _syncObject = new object(); _currentFragment = new FragmentedRemoteObject(); _queuedStreams = new Queue <MemoryStream>(); _fragmentSize = fragmentSize; }
internal SerializedDataStream (int fragmentSize) { if (fragmentSize == 0) { _trace.WriteLine("Error: SerializedDataStream with fragmentsize : {0}", new object[] { fragmentSize }); } _trace.WriteLine("Creating SerializedDataStream with fragmentsize : {0}", new object[] { fragmentSize }); this.syncObject = new object(); this.currentFragment = new FragmentedRemoteObject(); this.queuedStreams = new Queue<MemoryStream>(); this.fragmentSize = fragmentSize; }
internal SerializedDataStream(int fragmentSize) { if (fragmentSize == 0) { _trace.WriteLine("Error: SerializedDataStream with fragmentsize : {0}", new object[] { fragmentSize }); } _trace.WriteLine("Creating SerializedDataStream with fragmentsize : {0}", new object[] { fragmentSize }); this.syncObject = new object(); this.currentFragment = new FragmentedRemoteObject(); this.queuedStreams = new Queue <MemoryStream>(); this.fragmentSize = fragmentSize; }
/// <summary> /// Process data coming from the transport. This method analyses the data /// and if an object can be created, it creates one and calls the /// <paramref name="callback"/> with the deserialized object. This method /// does not assume all fragments to be available. So if not enough fragments are /// available it will simply return.. /// </summary> /// <param name="data"> /// Data to process. /// </param> /// <param name="callback"> /// Callback to call once a complete deserialized object is available. /// </param> /// <returns> /// Defragmented Object if any, otherwise null. /// </returns> /// <exception cref="PSRemotingTransportException"> /// 1. Fragment Ids not in sequence /// 2. Object Ids does not match /// 3. The current deserialized object size of the received data exceeded /// allowed maximum object size. The current deserialized object size is {0}. /// Allowed maximum object size is {1}. /// </exception> /// <remarks> /// Might throw other exceptions as the deserialized object is handled here. /// </remarks> internal void ProcessRawData(byte[] data, OnDataAvailableCallback callback) { Dbg.Assert(data != null, "Cannot process null data"); Dbg.Assert(callback != null, "Callback cannot be null"); lock (_syncObject) { if (_isDisposed) { return; } _numberOfThreadsProcessing++; if (_numberOfThreadsProcessing > _maxNumberOfThreadsToAllowForProcessing) { Dbg.Assert(false, "Multiple threads are not allowed in ProcessRawData."); } } try { _pendingDataStream.Write(data, 0, data.Length); // this do loop will process one deserialized object. // using a loop allows to process multiple objects within // the same packet while (true) { if (_pendingDataStream.Length <= FragmentedRemoteObject.HeaderLength) { // there is not enough data to be processed. s_baseTracer.WriteLine("Not enough data to process. Data is less than header length. Data length is {0}. Header Length {1}.", _pendingDataStream.Length, FragmentedRemoteObject.HeaderLength); return; } byte[] dataRead = _pendingDataStream.ToArray(); // there is enough data to process here. get the fragment header long objectId = FragmentedRemoteObject.GetObjectId(dataRead, 0); if (objectId <= 0) { throw new PSRemotingTransportException(RemotingErrorIdStrings.ObjectIdCannotBeLessThanZero); } long fragmentId = FragmentedRemoteObject.GetFragmentId(dataRead, 0); bool sFlag = FragmentedRemoteObject.GetIsStartFragment(dataRead, 0); bool eFlag = FragmentedRemoteObject.GetIsEndFragment(dataRead, 0); int blobLength = FragmentedRemoteObject.GetBlobLength(dataRead, 0); if ((s_baseTracer.Options & PSTraceSourceOptions.WriteLine) != PSTraceSourceOptions.None) { s_baseTracer.WriteLine("Object Id: {0}", objectId); s_baseTracer.WriteLine("Fragment Id: {0}", fragmentId); s_baseTracer.WriteLine("Start Flag: {0}", sFlag); s_baseTracer.WriteLine("End Flag: {0}", eFlag); s_baseTracer.WriteLine("Blob Length: {0}", blobLength); } int totalLengthOfFragment = 0; try { totalLengthOfFragment = checked (FragmentedRemoteObject.HeaderLength + blobLength); } catch (System.OverflowException) { s_baseTracer.WriteLine("Fragment too big."); ResetReceiveData(); PSRemotingTransportException e = new PSRemotingTransportException(RemotingErrorIdStrings.ObjectIsTooBig); throw e; } if (_pendingDataStream.Length < totalLengthOfFragment) { s_baseTracer.WriteLine("Not enough data to process packet. Data is less than expected blob length. Data length {0}. Expected Length {1}.", _pendingDataStream.Length, totalLengthOfFragment); return; } // ensure object size limit is not reached if (_maxReceivedObjectSize.HasValue) { _totalReceivedObjectSizeSoFar = unchecked (_totalReceivedObjectSizeSoFar + totalLengthOfFragment); if ((_totalReceivedObjectSizeSoFar < 0) || (_totalReceivedObjectSizeSoFar > _maxReceivedObjectSize.Value)) { s_baseTracer.WriteLine("ObjectSize > MaxReceivedObjectSize. ObjectSize is {0}. MaxReceivedObjectSize is {1}", _totalReceivedObjectSizeSoFar, _maxReceivedObjectSize); PSRemotingTransportException e = null; if (_isCreateByClientTM) { e = new PSRemotingTransportException(PSRemotingErrorId.ReceivedObjectSizeExceededMaximumClient, RemotingErrorIdStrings.ReceivedObjectSizeExceededMaximumClient, _totalReceivedObjectSizeSoFar, _maxReceivedObjectSize); } else { e = new PSRemotingTransportException(PSRemotingErrorId.ReceivedObjectSizeExceededMaximumServer, RemotingErrorIdStrings.ReceivedObjectSizeExceededMaximumServer, _totalReceivedObjectSizeSoFar, _maxReceivedObjectSize); } ResetReceiveData(); throw e; } } // appears like stream doesn't have individual position marker for read and write // since we are going to read from now... _pendingDataStream.Seek(0, SeekOrigin.Begin); // we have enough data to process..so read the data from the stream and process. byte[] oneFragment = new byte[totalLengthOfFragment]; // this will change position back to totalLengthOfFragment int dataCount = _pendingDataStream.Read(oneFragment, 0, totalLengthOfFragment); Dbg.Assert(dataCount == totalLengthOfFragment, "Unable to read enough data from the stream. Read failed"); PSEtwLog.LogAnalyticVerbose( PSEventId.ReceivedRemotingFragment, PSOpcode.Receive, PSTask.None, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, (Int64)objectId, (Int64)fragmentId, sFlag ? 1 : 0, eFlag ? 1 : 0, (UInt32)blobLength, new PSETWBinaryBlob(oneFragment, FragmentedRemoteObject.HeaderLength, blobLength)); byte[] extraData = null; if (totalLengthOfFragment < _pendingDataStream.Length) { // there is more data in the stream than fragment size..so save that data extraData = new byte[_pendingDataStream.Length - totalLengthOfFragment]; _pendingDataStream.Read(extraData, 0, (int)(_pendingDataStream.Length - totalLengthOfFragment)); } // reset incoming stream. _pendingDataStream.Dispose(); _pendingDataStream = new MemoryStream(); if (extraData != null) { _pendingDataStream.Write(extraData, 0, extraData.Length); } if (sFlag) { _canIgnoreOffSyncFragments = false; // reset this upon receiving a start fragment of a fresh object _currentObjectId = objectId; // Memory streams created with an unsigned byte array provide a non-resizable stream view // of the data, and can only be written to. When using a byte array, you can neither append // to nor shrink the stream, although you might be able to modify the existing contents // depending on the parameters passed into the constructor. Empty memory streams are // resizable, and can be written to and read from. _dataToProcessStream = new MemoryStream(); } else { // check if the data belongs to the same object as the start fragment if (objectId != _currentObjectId) { s_baseTracer.WriteLine("ObjectId != CurrentObjectId"); // TODO - drop an ETW event ResetReceiveData(); if (!_canIgnoreOffSyncFragments) { PSRemotingTransportException e = new PSRemotingTransportException(RemotingErrorIdStrings.ObjectIdsNotMatching); throw e; } else { s_baseTracer.WriteLine("Ignoring ObjectId != CurrentObjectId"); continue; } } if (fragmentId != (_currentFrgId + 1)) { s_baseTracer.WriteLine("Fragment Id is not in sequence."); // TODO - drop an ETW event ResetReceiveData(); if (!_canIgnoreOffSyncFragments) { PSRemotingTransportException e = new PSRemotingTransportException(RemotingErrorIdStrings.FragmentIdsNotInSequence); throw e; } else { s_baseTracer.WriteLine("Ignoring Fragment Id is not in sequence."); continue; } } } // make fragment id from this packet as the current fragment id _currentFrgId = fragmentId; // store the blob in a separate stream _dataToProcessStream.Write(oneFragment, FragmentedRemoteObject.HeaderLength, blobLength); if (eFlag) { try { // appears like stream doesn't individual position marker for read and write // since we are going to read from now..i am resetting position to 0. _dataToProcessStream.Seek(0, SeekOrigin.Begin); RemoteDataObject <PSObject> remoteObject = RemoteDataObject <PSObject> .CreateFrom(_dataToProcessStream, _defragmentor); s_baseTracer.WriteLine("Runspace Id: {0}", remoteObject.RunspacePoolId); s_baseTracer.WriteLine("PowerShell Id: {0}", remoteObject.PowerShellId); // notify the caller that a deserialized object is available. callback(remoteObject); } finally { // Reset the receive data buffers and start the process again. ResetReceiveData(); } if (_isDisposed) { break; } } } } finally { lock (_syncObject) { if (_isDisposed && (_numberOfThreadsProcessing == 1)) { ReleaseResources(); } _numberOfThreadsProcessing--; } } }
internal void ProcessRawData(byte[] data, OnDataAvailableCallback callback) { lock (this.syncObject) { if (this.isDisposed) { return; } this.numberOfThreadsProcessing++; int maxNumberOfThreadsToAllowForProcessing = this.maxNumberOfThreadsToAllowForProcessing; int numberOfThreadsProcessing = this.numberOfThreadsProcessing; } try { this.pendingDataStream.Write(data, 0, data.Length); Label_005A: if (this.pendingDataStream.Length <= 0x15L) { baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Not enough data to process. Data is less than header length. Data length is {0}. Header Length {1}.", new object[] { this.pendingDataStream.Length, 0x15 }), new object[0]); } else { byte[] fragmentBytes = this.pendingDataStream.GetBuffer(); long objectId = FragmentedRemoteObject.GetObjectId(fragmentBytes, 0); if (objectId <= 0L) { throw new PSRemotingTransportException(RemotingErrorIdStrings.ObjectIdCannotBeLessThanZero); } long fragmentId = FragmentedRemoteObject.GetFragmentId(fragmentBytes, 0); bool isStartFragment = FragmentedRemoteObject.GetIsStartFragment(fragmentBytes, 0); bool isEndFragment = FragmentedRemoteObject.GetIsEndFragment(fragmentBytes, 0); int blobLength = FragmentedRemoteObject.GetBlobLength(fragmentBytes, 0); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Object Id: {0}", new object[] { objectId }), new object[0]); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Fragment Id: {0}", new object[] { fragmentId }), new object[0]); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Start Flag: {0}", new object[] { isStartFragment }), new object[0]); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "End Flag: {0}", new object[] { isEndFragment }), new object[0]); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Blob Length: {0}", new object[] { blobLength }), new object[0]); int count = 0; try { count = 0x15 + blobLength; } catch (OverflowException) { baseTracer.WriteLine("Fragement too big.", new object[0]); this.ResetRecieveData(); PSRemotingTransportException exception = new PSRemotingTransportException(RemotingErrorIdStrings.ObjectIsTooBig); throw exception; } if (this.pendingDataStream.Length < count) { baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Not enough data to process packet. Data is less than expected blob length. Data length {0}. Expected Length {1}.", new object[] { this.pendingDataStream.Length, count }), new object[0]); } else { if (this.maxReceivedObjectSize.HasValue) { this.totalReceivedObjectSizeSoFar += count; if ((this.totalReceivedObjectSizeSoFar < 0) || (this.totalReceivedObjectSizeSoFar > this.maxReceivedObjectSize.Value)) { baseTracer.WriteLine("ObjectSize > MaxReceivedObjectSize. ObjectSize is {0}. MaxReceivedObjectSize is {1}", new object[] { this.totalReceivedObjectSizeSoFar, this.maxReceivedObjectSize }); PSRemotingTransportException exception2 = null; if (this.isCreateByClientTM) { exception2 = new PSRemotingTransportException(PSRemotingErrorId.ReceivedObjectSizeExceededMaximumClient, RemotingErrorIdStrings.ReceivedObjectSizeExceededMaximumClient, new object[] { this.totalReceivedObjectSizeSoFar, this.maxReceivedObjectSize }); } else { exception2 = new PSRemotingTransportException(PSRemotingErrorId.ReceivedObjectSizeExceededMaximumServer, RemotingErrorIdStrings.ReceivedObjectSizeExceededMaximumServer, new object[] { this.totalReceivedObjectSizeSoFar, this.maxReceivedObjectSize }); } this.ResetRecieveData(); throw exception2; } } this.pendingDataStream.Seek(0L, SeekOrigin.Begin); byte[] buffer = new byte[count]; this.pendingDataStream.Read(buffer, 0, count); PSEtwLog.LogAnalyticVerbose(PSEventId.ReceivedRemotingFragment, PSOpcode.Receive, PSTask.None, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, objectId, fragmentId, isStartFragment ? 1 : 0, isEndFragment ? 1 : 0, (int)blobLength, new PSETWBinaryBlob(buffer, 0x15, blobLength)); byte[] buffer3 = null; if (count < this.pendingDataStream.Length) { buffer3 = new byte[this.pendingDataStream.Length - count]; this.pendingDataStream.Read(buffer3, 0, ((int)this.pendingDataStream.Length) - count); } this.pendingDataStream.Close(); this.pendingDataStream = new MemoryStream(); if (buffer3 != null) { this.pendingDataStream.Write(buffer3, 0, buffer3.Length); } if (isStartFragment) { this.canIgnoreOffSyncFragments = false; this.currentObjectId = objectId; this.dataToProcessStream = new MemoryStream(); } else { if (objectId != this.currentObjectId) { baseTracer.WriteLine("ObjectId != CurrentObjectId", new object[0]); this.ResetRecieveData(); if (!this.canIgnoreOffSyncFragments) { PSRemotingTransportException exception3 = new PSRemotingTransportException(RemotingErrorIdStrings.ObjectIdsNotMatching); throw exception3; } baseTracer.WriteLine("Ignoring ObjectId != CurrentObjectId", new object[0]); goto Label_005A; } if (fragmentId != (this.currentFrgId + 1L)) { baseTracer.WriteLine("Fragment Id is not in sequence.", new object[0]); this.ResetRecieveData(); if (!this.canIgnoreOffSyncFragments) { PSRemotingTransportException exception4 = new PSRemotingTransportException(RemotingErrorIdStrings.FragmetIdsNotInSequence); throw exception4; } baseTracer.WriteLine("Ignoring Fragment Id is not in sequence.", new object[0]); goto Label_005A; } } this.currentFrgId = fragmentId; this.dataToProcessStream.Write(buffer, 0x15, blobLength); if (!isEndFragment) { goto Label_005A; } try { this.dataToProcessStream.Seek(0L, SeekOrigin.Begin); RemoteDataObject <PSObject> obj2 = RemoteDataObject <PSObject> .CreateFrom(this.dataToProcessStream, this.defragmentor); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "Runspace Id: {0}", new object[] { obj2.RunspacePoolId }), new object[0]); baseTracer.WriteLine(string.Format(CultureInfo.InvariantCulture, "PowerShell Id: {0}", new object[] { obj2.PowerShellId }), new object[0]); callback(obj2); } finally { this.ResetRecieveData(); } if (!this.isDisposed && this.pendingDataStream.Length > 0x15L) { goto Label_005A; } } } } finally { lock (this.syncObject) { if (this.isDisposed && (this.numberOfThreadsProcessing == 1)) { this.ReleaseResources(); } this.numberOfThreadsProcessing--; } } }
internal void ExecuteConnect(byte[] connectData, out byte[] connectResponseData) { RemoteSessionCapability sessionCapability; connectResponseData = null; Fragmentor fragmentor = new Fragmentor(0x7fffffff, null); Fragmentor defragmentor = fragmentor; int length = connectData.Length; if (length < 0x15) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } FragmentedRemoteObject.GetFragmentId(connectData, 0); bool isStartFragment = FragmentedRemoteObject.GetIsStartFragment(connectData, 0); bool isEndFragment = FragmentedRemoteObject.GetIsEndFragment(connectData, 0); int blobLength = FragmentedRemoteObject.GetBlobLength(connectData, 0); if (blobLength > (length - 0x15)) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } if (!isStartFragment || !isEndFragment) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } RemoteSessionState state = this.SessionDataStructureHandler.StateMachine.State; if ((state != RemoteSessionState.Established) && (state != RemoteSessionState.EstablishedAndKeyExchanged)) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnServerStateValidation); } MemoryStream serializedDataStream = new MemoryStream(); serializedDataStream.Write(connectData, 0x15, blobLength); serializedDataStream.Seek(0L, SeekOrigin.Begin); RemoteDataObject <PSObject> obj2 = RemoteDataObject <PSObject> .CreateFrom(serializedDataStream, defragmentor); if (obj2 == null) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } if ((obj2.Destination != (RemotingDestination.InvalidDestination | RemotingDestination.Server)) || (obj2.DataType != RemotingDataType.SessionCapability)) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } int num3 = (length - 0x15) - blobLength; if (num3 < 0x15) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } byte[] destinationArray = new byte[num3]; Array.Copy(connectData, 0x15 + blobLength, destinationArray, 0, num3); FragmentedRemoteObject.GetFragmentId(destinationArray, 0); isStartFragment = FragmentedRemoteObject.GetIsStartFragment(destinationArray, 0); isEndFragment = FragmentedRemoteObject.GetIsEndFragment(destinationArray, 0); blobLength = FragmentedRemoteObject.GetBlobLength(destinationArray, 0); if (blobLength != (num3 - 0x15)) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } if (!isStartFragment || !isEndFragment) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } serializedDataStream = new MemoryStream(); serializedDataStream.Write(destinationArray, 0x15, blobLength); serializedDataStream.Seek(0L, SeekOrigin.Begin); RemoteDataObject <PSObject> obj3 = RemoteDataObject <PSObject> .CreateFrom(serializedDataStream, defragmentor); if (obj3 == null) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnServerStateValidation); } if ((obj3.Destination != (RemotingDestination.InvalidDestination | RemotingDestination.Server)) || (obj3.DataType != RemotingDataType.ConnectRunspacePool)) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } try { sessionCapability = RemotingDecoder.GetSessionCapability(obj2.Data); } catch (PSRemotingDataStructureException) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } try { this.RunServerNegotiationAlgorithm(sessionCapability, true); } catch (PSRemotingDataStructureException exception) { throw exception; } int minRunspaces = -1; int maxRunspaces = -1; bool flag3 = false; if ((obj3.Data.Properties["MinRunspaces"] != null) && (obj3.Data.Properties["MinRunspaces"] != null)) { try { minRunspaces = RemotingDecoder.GetMinRunspaces(obj3.Data); maxRunspaces = RemotingDecoder.GetMaxRunspaces(obj3.Data); flag3 = true; } catch (PSRemotingDataStructureException) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } } if (flag3 && (((minRunspaces == -1) || (maxRunspaces == -1)) || (minRunspaces > maxRunspaces))) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } if (this._runspacePoolDriver == null) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnServerStateValidation); } if (obj3.RunspacePoolId != this._runspacePoolDriver.InstanceId) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnInputValidation); } if ((flag3 && (this._runspacePoolDriver.RunspacePool.GetMaxRunspaces() != maxRunspaces)) && (this._runspacePoolDriver.RunspacePool.GetMinRunspaces() != minRunspaces)) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerConnectFailedOnMismatchedRunspacePoolProperties); } RemoteDataObject obj4 = RemotingEncoder.GenerateServerSessionCapability(this._context.ServerCapability, this._runspacePoolDriver.InstanceId); RemoteDataObject obj5 = RemotingEncoder.GenerateRunspacePoolInitData(this._runspacePoolDriver.InstanceId, this._runspacePoolDriver.RunspacePool.GetMaxRunspaces(), this._runspacePoolDriver.RunspacePool.GetMinRunspaces()); SerializedDataStream streamToWriteTo = new SerializedDataStream(0x1000); streamToWriteTo.Enter(); obj4.Serialize(streamToWriteTo, fragmentor); streamToWriteTo.Exit(); streamToWriteTo.Enter(); obj5.Serialize(streamToWriteTo, fragmentor); streamToWriteTo.Exit(); byte[] buffer2 = streamToWriteTo.Read(); streamToWriteTo.Dispose(); connectResponseData = buffer2; ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object s) { RemoteSessionStateMachineEventArgs fsmEventArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.ConnectSession); this._sessionDSHandler.StateMachine.RaiseEvent(fsmEventArg); })); this._runspacePoolDriver.DataStructureHandler.ProcessConnect(); }