Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
RemotingProtocol2.cs1635 linesDownload Raw Back to client
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Management.Automation.Host;7using System.Management.Automation.Remoting;8using System.Management.Automation.Remoting.Client;9using System.Management.Automation.Runspaces;10using System.Management.Automation.Runspaces.Internal;11using System.Management.Automation.Tracing;12using System.Threading;13 14using Dbg = System.Management.Automation.Diagnostics;15 16namespace System.Management.Automation.Internal17{18    /// <summary>19    /// Handles all PowerShell data structure handler communication with the20    /// server side RunspacePool.21    /// </summary>22    internal sealed class ClientRunspacePoolDataStructureHandler : IDisposable23    {24        private bool _reconnecting = false;25 26        #region Constructors27 28        /// <summary>29        /// Constructor which takes a client runspace pool and creates30        /// an associated ClientRunspacePoolDataStructureHandler.31        /// </summary>32        /// <param name="clientRunspacePool">Client runspace pool object.</param>33        /// <param name="typeTable">Typetable to use for serialization/deserialization.</param>34        internal ClientRunspacePoolDataStructureHandler(RemoteRunspacePoolInternal clientRunspacePool,35            TypeTable typeTable)36        {37            _clientRunspacePoolId = clientRunspacePool.InstanceId;38            _minRunspaces = clientRunspacePool.GetMinRunspaces();39            _maxRunspaces = clientRunspacePool.GetMaxRunspaces();40            _host = clientRunspacePool.Host;41            _applicationArguments = clientRunspacePool.ApplicationArguments;42            RemoteSession = CreateClientRemoteSession(clientRunspacePool);43            // TODO: Assign remote session name.. should be passed from clientRunspacePool44            _transportManager = RemoteSession.SessionDataStructureHandler.TransportManager;45            _transportManager.TypeTable = typeTable;46            RemoteSession.StateChanged += HandleClientRemoteSessionStateChanged;47            _reconnecting = false;48 49            _transportManager.RobustConnectionNotification += HandleRobustConnectionNotification;50            _transportManager.CreateCompleted += HandleSessionCreateCompleted;51        }52 53        #endregion Constructors54 55        #region Data Structure Handler Methods56 57        /// <summary>58        /// Create a runspace pool asynchronously (and opens) it59        /// on the server.60        /// </summary>61        internal void CreateRunspacePoolAndOpenAsync()62        {63            // #1: Connect to remote session64            Dbg.Assert(RemoteSession.SessionDataStructureHandler.StateMachine.State == RemoteSessionState.Idle,65                "State of ClientRemoteSession is expected to be idle before connection is established");66            RemoteSession.CreateAsync();67 68            // #2: send the message for runspace pool creation69            // this is done in HandleClientRemoteSessionStateChanged70        }71 72        /// <summary>73        /// Closes the server runspace pool asynchronously.74        /// </summary>75        internal void CloseRunspacePoolAsync()76        {77            RemoteSession.CloseAsync();78        }79 80        /// <summary>81        /// Suspends connection to a runspace pool asynchronously.82        /// </summary>83        internal void DisconnectPoolAsync()84        {85            // Prepare running commands for disconnect and start disconnect86            // when ready.87            PrepareForAndStartDisconnect();88        }89 90        /// <summary>91        /// Restore connection to a runspace pool asynchronously.92        /// </summary>93        internal void ReconnectPoolAsync()94        {95            // TODO: Integrate this into state machine96            _reconnecting = true;97            PrepareForConnect();98            RemoteSession.ReconnectAsync();99        }100 101        /// <summary>102        /// Creates a connection to an existing remote runspace pool.103        /// </summary>104        internal void ConnectPoolAsync()105        {106            PrepareForConnect();107            RemoteSession.ConnectAsync();108        }109 110        /// <summary>111        /// Process the data received from the runspace pool112        /// on the server.113        /// </summary>114        /// <param name="receivedData">Data received.</param>115        internal void ProcessReceivedData(RemoteDataObject<PSObject> receivedData)116        {117            // verify if this data structure handler is the intended recipient118            if (receivedData.RunspacePoolId != _clientRunspacePoolId)119            {120                throw new PSRemotingDataStructureException(RemotingErrorIdStrings.RunspaceIdsDoNotMatch,121                                receivedData.RunspacePoolId, _clientRunspacePoolId);122            }123 124            // take appropriate action based on the action type125            Dbg.Assert(receivedData.TargetInterface == RemotingTargetInterface.RunspacePool,126                "Target interface is expected to be RunspacePool");127 128            switch (receivedData.DataType)129            {130                case RemotingDataType.RemoteHostCallUsingRunspaceHost:131                    {132                        Dbg.Assert(RemoteHostCallReceived != null,133                            "RemoteRunspacePoolInternal should subscribe to all data structure handler events");134 135                        RemoteHostCall remoteHostCall = RemoteHostCall.Decode(receivedData.Data);136                        RemoteHostCallReceived.SafeInvoke(this, new RemoteDataEventArgs<RemoteHostCall>(remoteHostCall));137                    }138 139                    break;140 141                case RemotingDataType.RunspacePoolInitData:142                    {143                        RunspacePoolInitInfo initInfo = RemotingDecoder.GetRunspacePoolInitInfo(receivedData.Data);144 145                        Dbg.Assert(RSPoolInitInfoReceived != null,146                            "RemoteRunspacePoolInternal should subscribe to all data structure handler events");147                        RSPoolInitInfoReceived.SafeInvoke(this,148                            new RemoteDataEventArgs<RunspacePoolInitInfo>(initInfo));149                    }150 151                    break;152 153                case RemotingDataType.RunspacePoolStateInfo:154                    {155                        RunspacePoolStateInfo stateInfo =156                            RemotingDecoder.GetRunspacePoolStateInfo(receivedData.Data);157 158                        Dbg.Assert(StateInfoReceived != null,159                            "RemoteRunspacePoolInternal should subscribe to all data structure handler events");160                        StateInfoReceived.SafeInvoke(this,161                            new RemoteDataEventArgs<RunspacePoolStateInfo>(stateInfo));162 163                        NotifyAssociatedPowerShells(stateInfo);164                    }165 166                    break;167 168                case RemotingDataType.ApplicationPrivateData:169                    {170                        PSPrimitiveDictionary applicationPrivateData = RemotingDecoder.GetApplicationPrivateData(receivedData.Data);171                        Dbg.Assert(ApplicationPrivateDataReceived != null,172                            "RemoteRunspacePoolInternal should subscribe to all data structure handler events");173                        ApplicationPrivateDataReceived.SafeInvoke(this,174                            new RemoteDataEventArgs<PSPrimitiveDictionary>(applicationPrivateData));175                    }176 177                    break;178 179                case RemotingDataType.RunspacePoolOperationResponse:180                    {181                        Dbg.Assert(SetMaxMinRunspacesResponseReceived != null,182                            "RemoteRunspacePoolInternal should subscribe to all data structure handler events");183 184                        SetMaxMinRunspacesResponseReceived.SafeInvoke(this, new RemoteDataEventArgs<PSObject>(receivedData.Data));185                    }186 187                    break;188 189                case RemotingDataType.PSEventArgs:190                    {191                        PSEventArgs psEventArgs = RemotingDecoder.GetPSEventArgs(receivedData.Data);192 193                        Dbg.Assert(PSEventArgsReceived != null,194                            "RemoteRunspacePoolInternal should subscribe to all data structure handler events");195 196                        PSEventArgsReceived.SafeInvoke(this, new RemoteDataEventArgs<PSEventArgs>(psEventArgs));197                    }198 199                    break;200            }201        }202 203        /// <summary>204        /// Creates a PowerShell data structure handler instance associated205        /// with this runspace pool data structure handler.206        /// </summary>207        /// <param name="shell">Associated powershell.</param>208        /// <returns>PowerShell data structure handler object.</returns>209        internal ClientPowerShellDataStructureHandler CreatePowerShellDataStructureHandler(210            ClientRemotePowerShell shell)211        {212            BaseClientCommandTransportManager clientTransportMgr =213                RemoteSession.SessionDataStructureHandler.CreateClientCommandTransportManager(shell, shell.NoInput);214 215            return new ClientPowerShellDataStructureHandler(216                clientTransportMgr, _clientRunspacePoolId, shell.InstanceId);217        }218 219        /// <summary>220        /// Creates a PowerShell instances on the server, associates it221        /// with this runspace pool and invokes.222        /// </summary>223        /// <param name="shell">The client remote powershell.</param>224        internal void CreatePowerShellOnServerAndInvoke(ClientRemotePowerShell shell)225        {226            // add to associated powershell list and send request to server227            lock (_associationSyncObject)228            {229                _associatedPowerShellDSHandlers.Add(shell.InstanceId, shell.DataStructureHandler);230            }231 232            shell.DataStructureHandler.RemoveAssociation += HandleRemoveAssociation;233 234            // Find out if this is an invoke and disconnect operation and if so whether the endpoint235            // supports disconnect.  Throw exception if disconnect is not supported.236            bool invokeAndDisconnect = shell.Settings != null && shell.Settings.InvokeAndDisconnect;237            if (invokeAndDisconnect && !EndpointSupportsDisconnect)238            {239                throw new PSRemotingDataStructureException(RemotingErrorIdStrings.EndpointDoesNotSupportDisconnect);240            }241 242            if (RemoteSession == null)243            {244                throw new ObjectDisposedException("ClientRunspacePoolDataStructureHandler");245            }246 247            shell.DataStructureHandler.Start(RemoteSession.SessionDataStructureHandler.StateMachine, invokeAndDisconnect);248        }249 250        /// <summary>251        /// Add a ClientPowerShellDataStructureHandler to association list.252        /// </summary>253        /// <param name="psShellInstanceId">PowerShell Instance Id.</param>254        /// <param name="psDSHandler">ClientPowerShellDataStructureHandler for PowerShell.</param>255        internal void AddRemotePowerShellDSHandler(Guid psShellInstanceId, ClientPowerShellDataStructureHandler psDSHandler)256        {257            lock (_associationSyncObject)258            {259                // Remove old DSHandler and replace with new.260                _associatedPowerShellDSHandlers[psShellInstanceId] = psDSHandler;261            }262 263            psDSHandler.RemoveAssociation += HandleRemoveAssociation;264        }265 266        /// <summary>267        /// Dispatch the message to the associated powershell data structure handler.268        /// </summary>269        /// <param name="rcvdData">Message received.</param>270        internal void DispatchMessageToPowerShell(RemoteDataObject<PSObject> rcvdData)271        {272            ClientPowerShellDataStructureHandler dsHandler =273                GetAssociatedPowerShellDataStructureHandler(rcvdData.PowerShellId);274 275            // if a data structure handler does not exist it means276            // the association has been removed -277            // discard messages278            dsHandler?.ProcessReceivedData(rcvdData);279        }280 281        /// <summary>282        /// Send the host response to the server.283        /// </summary>284        /// <param name="hostResponse">Host response object to send.</param>285        internal void SendHostResponseToServer(RemoteHostResponse hostResponse)286        {287            SendDataAsync(hostResponse.Encode(), DataPriorityType.PromptResponse);288        }289 290        /// <summary>291        /// Send a message to the server instructing it to reset its runspace state.292        /// </summary>293        /// <param name="callId">Caller Id.</param>294        internal void SendResetRunspaceStateToServer(long callId)295        {296            RemoteDataObject message =297                RemotingEncoder.GenerateResetRunspaceState(_clientRunspacePoolId, callId);298 299            SendDataAsync(message);300        }301 302        /// <summary>303        /// Sent a message to modify the max runspaces of the runspace pool.304        /// </summary>305        /// <param name="maxRunspaces">New maxrunspaces to set.</param>306        /// <param name="callId">call id on which the calling method will307        /// be blocked on</param>308        internal void SendSetMaxRunspacesToServer(int maxRunspaces, long callId)309        {310            RemoteDataObject message =311                RemotingEncoder.GenerateSetMaxRunspaces(_clientRunspacePoolId, maxRunspaces, callId);312 313            SendDataAsync(message);314        }315 316        /// <summary>317        /// Send a message to modify the min runspaces of the runspace pool.318        /// </summary>319        /// <param name="minRunspaces">New minrunspaces to set.</param>320        /// <param name="callId">call id on which the calling method will321        /// be blocked on</param>322        internal void SendSetMinRunspacesToServer(int minRunspaces, long callId)323        {324            RemoteDataObject message =325                RemotingEncoder.GenerateSetMinRunspaces(_clientRunspacePoolId, minRunspaces, callId);326 327            SendDataAsync(message);328        }329 330        /// <summary>331        /// Send a message to get the available runspaces from the server.332        /// </summary>333        /// <param name="callId">call id on which the calling method will334        /// be blocked on</param>335        internal void SendGetAvailableRunspacesToServer(long callId)336        {337            SendDataAsync(RemotingEncoder.GenerateGetAvailableRunspaces(_clientRunspacePoolId, callId));338        }339 340        #endregion Data Structure Handler Methods341 342        #region Data Structure Handler events343 344        /// <summary>345        /// Event raised when a host call is received.346        /// </summary>347        internal event EventHandler<RemoteDataEventArgs<RemoteHostCall>> RemoteHostCallReceived;348 349        /// <summary>350        /// Event raised when state information is received.351        /// </summary>352        internal event EventHandler<RemoteDataEventArgs<RunspacePoolStateInfo>> StateInfoReceived;353 354        /// <summary>355        /// Event raised when RunspacePoolInitInfo is received. This is the first runspace pool message expected356        /// after connecting to an existing remote runspace pool. RemoteRunspacePoolInternal should use this357        /// notification to set the state of a reconstructed runspace to "Opened State" and use the358        /// minRunspace and MaxRunspaces information to set its state.359        /// </summary>360        internal event EventHandler<RemoteDataEventArgs<RunspacePoolInitInfo>> RSPoolInitInfoReceived;361 362        /// <summary>363        /// Event raised when application private data is received.364        /// </summary>365        internal event EventHandler<RemoteDataEventArgs<PSPrimitiveDictionary>> ApplicationPrivateDataReceived;366 367        /// <summary>368        /// Event raised when a PSEventArgs is received.369        /// </summary>370        internal event EventHandler<RemoteDataEventArgs<PSEventArgs>> PSEventArgsReceived;371 372        /// <summary>373        /// Event raised when the session is closed.374        /// </summary>375        internal event EventHandler<RemoteDataEventArgs<Exception>> SessionClosed;376 377        /// <summary>378        /// </summary>379        internal event EventHandler<RemoteDataEventArgs<Exception>> SessionDisconnected;380 381        /// <summary>382        /// </summary>383        internal event EventHandler<RemoteDataEventArgs<Exception>> SessionReconnected;384 385        /// <summary>386        /// Event raised when the session is closing.387        /// </summary>388        internal event EventHandler<RemoteDataEventArgs<Exception>> SessionClosing;389 390        /// <summary>391        /// Event raised when a response to a SetMaxRunspaces or SetMinRunspaces call392        /// is received.393        /// </summary>394        internal event EventHandler<RemoteDataEventArgs<PSObject>> SetMaxMinRunspacesResponseReceived;395 396        /// <summary>397        /// EventHandler used to report connection URI redirections to the application.398        /// </summary>399        internal event EventHandler<RemoteDataEventArgs<Uri>> URIRedirectionReported;400 401        /// <summary>402        /// Indicates that a disconnect has been initiated by the WinRM robust connections layer.403        /// </summary>404        internal event EventHandler<RemoteDataEventArgs<Exception>> SessionRCDisconnecting;405 406        /// <summary>407        /// Notification that session creation has completed.408        /// </summary>409        internal event EventHandler<CreateCompleteEventArgs> SessionCreateCompleted;410 411        #endregion Data Structure Handler events412 413        #region Private Methods414 415        /// <summary>416        /// Send the data specified as a RemoteDataObject asynchronously417        /// to the runspace pool on the remote session.418        /// </summary>419        /// <param name="data">Data to send.</param>420        /// <remarks>This overload takes a RemoteDataObject and should be421        /// the one used within the code</remarks>422        private void SendDataAsync(RemoteDataObject data)423        {424            _transportManager.DataToBeSentCollection.Add<object>(data);425        }426 427        /// <summary>428        /// Send the data asynchronously to runspace pool driver on remote429        /// session with the specified priority.430        /// </summary>431        /// <typeparam name="T"></typeparam>432        /// <param name="data">Data to be sent to server.</param>433        /// <param name="priority">Priority with which to send data.</param>434        internal void SendDataAsync<T>(RemoteDataObject<T> data, DataPriorityType priority)435        {436            _transportManager.DataToBeSentCollection.Add<T>(data, priority);437        }438 439        /// <summary>440        /// Send the data asynchronously to runspace pool driver on remote441        /// session with the specified priority.442        /// </summary>443        /// <param name="data">Data object to send.</param>444        /// <param name="priority">Priority with which to send data.</param>445        internal void SendDataAsync(PSObject data, DataPriorityType priority)446        {447            RemoteDataObject<PSObject> dataToBeSent = RemoteDataObject<PSObject>.CreateFrom(RemotingDestination.Server,448                RemotingDataType.InvalidDataType, _clientRunspacePoolId, Guid.Empty, data);449 450            _transportManager.DataToBeSentCollection.Add<PSObject>(dataToBeSent);451        }452 453        /// <summary>454        /// Create a client remote session based on the connection info.455        /// </summary>456        /// <param name="rsPoolInternal">457        /// The RunspacePool object this session should map to.458        /// </param>459        private ClientRemoteSessionImpl CreateClientRemoteSession(460                    RemoteRunspacePoolInternal rsPoolInternal)461        {462            ClientRemoteSession.URIDirectionReported uriRedirectionHandler =463                new ClientRemoteSession.URIDirectionReported(HandleURIDirectionReported);464            return new ClientRemoteSessionImpl(rsPoolInternal,465                                               uriRedirectionHandler);466        }467 468        /// <summary>469        /// Handler for handling all session events.470        /// </summary>471        /// <param name="sender">Sender of this event.</param>472        /// <param name="e">Object describing this event.</param>473        private void HandleClientRemoteSessionStateChanged(474                        object sender, RemoteSessionStateEventArgs e)475        {476            // send create runspace request while sending negotiation packet. This will477            // save 1 network call to create a runspace on the server.478            if (e.SessionStateInfo.State == RemoteSessionState.NegotiationSending)479            {480                if (_createRunspaceCalled)481                {482                    return;483                }484 485                lock (_syncObject)486                {487                    // We are doing this check because Established event488                    // is raised more than once489                    if (_createRunspaceCalled)490                    {491                        // TODO: Put an assert here. NegotiationSending cannot492                        // occur multiple time in v2 remoting.493                        return;494                    }495 496                    _createRunspaceCalled = true;497                }498 499                // make client's PSVersionTable available to the server using applicationArguments500                PSPrimitiveDictionary argumentsWithVersionTable =501                    PSPrimitiveDictionary.CloneAndAddPSVersionTable(_applicationArguments);502                // send a message to the server..503                SendDataAsync(RemotingEncoder.GenerateCreateRunspacePool(504                    _clientRunspacePoolId, _minRunspaces, _maxRunspaces, RemoteSession.RemoteRunspacePoolInternal, _host,505                    argumentsWithVersionTable));506            }507 508            if (e.SessionStateInfo.State == RemoteSessionState.NegotiationSendingOnConnect)509            {510                // send connect message to the server.511                SendDataAsync(RemotingEncoder.GenerateConnectRunspacePool(512                    _clientRunspacePoolId, _minRunspaces, _maxRunspaces));513            }514            else if (e.SessionStateInfo.State == RemoteSessionState.ClosingConnection)515            {516                // use the first reason which caused the error517                Exception reason = _closingReason;518                if (reason == null)519                {520                    reason = e.SessionStateInfo.Reason;521                    _closingReason = reason;522                }523 524                // close transport managers of the associated commands525                List<ClientPowerShellDataStructureHandler> dsHandlers;526                lock (_associationSyncObject)527                {528                    dsHandlers = new List<ClientPowerShellDataStructureHandler>(_associatedPowerShellDSHandlers.Values);529                }530 531                foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)532                {533                    dsHandler.CloseConnectionAsync(_closingReason);534                }535 536                SessionClosing.SafeInvoke(this, new RemoteDataEventArgs<Exception>(reason));537            }538            else if (e.SessionStateInfo.State == RemoteSessionState.Closed)539            {540                // use the first reason which caused the error541                Exception reason = _closingReason;542                if (reason == null)543                {544                    reason = e.SessionStateInfo.Reason;545                    _closingReason = reason;546                }547 548                // if there is a reason associated, then most likely the549                // runspace pool has broken, so notify accordingly550                if (reason != null)551                {552                    NotifyAssociatedPowerShells(new RunspacePoolStateInfo(RunspacePoolState.Broken, reason));553                }554                else555                {556                    // notify the associated powershells that this557                    // runspace pool has closed558                    NotifyAssociatedPowerShells(new RunspacePoolStateInfo(RunspacePoolState.Closed, reason));559                }560 561                SessionClosed.SafeInvoke(this, new RemoteDataEventArgs<Exception>(reason));562            }563            else if (e.SessionStateInfo.State == RemoteSessionState.Connected)564            {565                // write a transfer event here566                PSEtwLog.ReplaceActivityIdForCurrentThread(_clientRunspacePoolId, PSEventId.OperationalTransferEventRunspacePool,567                    PSEventId.AnalyticTransferEventRunspacePool, PSKeyword.Runspace, PSTask.CreateRunspace);568            }569            else if (e.SessionStateInfo.State == RemoteSessionState.Disconnected)570            {571                NotifyAssociatedPowerShells(new RunspacePoolStateInfo(572                    RunspacePoolState.Disconnected,573                    e.SessionStateInfo.Reason));574                SessionDisconnected.SafeInvoke(this, new RemoteDataEventArgs<Exception>(e.SessionStateInfo.Reason));575            }576            else if (_reconnecting && e.SessionStateInfo.State == RemoteSessionState.Established)577            {578                SessionReconnected.SafeInvoke(this, new RemoteDataEventArgs<Exception>(null));579                _reconnecting = false;580            }581            else if (e.SessionStateInfo.State == RemoteSessionState.RCDisconnecting)582            {583                SessionRCDisconnecting.SafeInvoke(this, new RemoteDataEventArgs<Exception>(null));584            }585            else586            {587                if (e.SessionStateInfo.Reason != null)588                {589                    _closingReason = e.SessionStateInfo.Reason;590                }591            }592        }593 594        /// <summary>595        /// Session is reporting that URI is getting redirected.596        /// Report this information to the user by writing a warning message.597        /// </summary>598        /// <param name="newURI"></param>599        private void HandleURIDirectionReported(Uri newURI)600        {601            URIRedirectionReported.SafeInvoke(this, new RemoteDataEventArgs<Uri>(newURI));602        }603 604        /// <summary>605        /// Notifies associated powershell's of the runspace pool state change.606        /// </summary>607        /// <param name="stateInfo">state information that need to608        /// be notified</param>609        private void NotifyAssociatedPowerShells(RunspacePoolStateInfo stateInfo)610        {611            List<ClientPowerShellDataStructureHandler> dsHandlers;612 613            if (stateInfo.State == RunspacePoolState.Disconnected)614            {615                lock (_associationSyncObject)616                {617                    dsHandlers = new List<ClientPowerShellDataStructureHandler>(_associatedPowerShellDSHandlers.Values);618                }619 620                foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)621                {622                    dsHandler.ProcessDisconnect(stateInfo);623                }624 625                return;626            }627 628            // if the runspace pool is broken or closed then set all629            // associated powershells to stopped630            if (stateInfo.State == RunspacePoolState.Broken || stateInfo.State == RunspacePoolState.Closed)631            {632                lock (_associationSyncObject)633                {634                    dsHandlers = new List<ClientPowerShellDataStructureHandler>(_associatedPowerShellDSHandlers.Values);635                    _associatedPowerShellDSHandlers.Clear();636                }637 638                if (stateInfo.State == RunspacePoolState.Broken)639                {640                    // set the state to failed, outside the lock641                    foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)642                    {643                        dsHandler.SetStateToFailed(stateInfo.Reason);644                    }645                }646                else if (stateInfo.State == RunspacePoolState.Closed)647                {648                    foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)649                    {650                        dsHandler.SetStateToStopped(stateInfo.Reason);651                    }652                }653 654                return;655            }656        }657 658        /// <summary>659        /// Gets the ClientPowerShellDataStructureHandler instance for the specified id.660        /// </summary>661        /// <param name="clientPowerShellId">Id of the client remote powershell.</param>662        /// <returns>ClientPowerShellDataStructureHandler object.</returns>663        private ClientPowerShellDataStructureHandler GetAssociatedPowerShellDataStructureHandler664            (Guid clientPowerShellId)665        {666            ClientPowerShellDataStructureHandler dsHandler = null;667 668            lock (_associationSyncObject)669            {670                bool success = _associatedPowerShellDSHandlers.TryGetValue(clientPowerShellId, out dsHandler);671 672                if (!success)673                {674                    dsHandler = null;675                }676            }677 678            return dsHandler;679        }680 681        /// <summary>682        /// Remove the association of the powershell from the runspace pool.683        /// </summary>684        /// <param name="sender">Sender of this event.</param>685        /// <param name="e">Unused.</param>686        private void HandleRemoveAssociation(object sender, EventArgs e)687        {688            Dbg.Assert(sender is ClientPowerShellDataStructureHandler, @"sender of the event689                must be ClientPowerShellDataStructureHandler");690 691            ClientPowerShellDataStructureHandler dsHandler =692                sender as ClientPowerShellDataStructureHandler;693 694            lock (_associationSyncObject)695            {696                _associatedPowerShellDSHandlers.Remove(dsHandler.PowerShellId);697            }698 699            _transportManager.RemoveCommandTransportManager(dsHandler.PowerShellId);700        }701 702        /// <summary>703        /// Calls each running command Transport manager PrepareForDisconnect method.704        /// Each transport manager object will raise an event when the command/transport705        /// is ready to be disconnected.  Disconnect will begin when all is ready.706        /// </summary>707        private void PrepareForAndStartDisconnect()708        {709            bool startDisconnectNow;710 711            lock (_associationSyncObject)712            {713                if (_associatedPowerShellDSHandlers.Count == 0)714                {715                    // There are no running commands associated with this runspace pool.716                    startDisconnectNow = true;717                    _preparingForDisconnectList = null;718                }719                else720                {721                    // Delay starting the disconnect operation until all running commands are prepared.722                    startDisconnectNow = false;723 724                    // Create and fill list of active transportmanager objects to be disconnected.725                    // Add ready-for-disconnect callback handler to DSHandler transportmanager objects.726                    Dbg.Assert(_preparingForDisconnectList == null, "Cannot prepare for disconnect while disconnect is pending.");727                    _preparingForDisconnectList = new List<BaseClientCommandTransportManager>();728                    foreach (ClientPowerShellDataStructureHandler dsHandler in _associatedPowerShellDSHandlers.Values)729                    {730                        _preparingForDisconnectList.Add(dsHandler.TransportManager);731                        dsHandler.TransportManager.ReadyForDisconnect += HandleReadyForDisconnect;732                    }733                }734            }735 736            if (startDisconnectNow)737            {738                // Ok to start on this thread.739                StartDisconnectAsync(RemoteSession);740            }741            else742            {743                // Start preparation for disconnect.  The HandleReadyForDisconnect callback will be744                // called when a transportManager is ready for disconnect.745                List<ClientPowerShellDataStructureHandler> dsHandlers;746                lock (_associationSyncObject)747                {748                    dsHandlers = new List<ClientPowerShellDataStructureHandler>(_associatedPowerShellDSHandlers.Values);749                }750 751                foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)752                {753                    dsHandler.TransportManager.PrepareForDisconnect();754                }755            }756        }757 758        /// <summary>759        /// Allows each running command to resume processing command input for when760        /// the runspacepool and running commands are connected.761        /// </summary>762        private void PrepareForConnect()763        {764            List<ClientPowerShellDataStructureHandler> dsHandlers;765            lock (_associationSyncObject)766            {767                dsHandlers = new List<ClientPowerShellDataStructureHandler>(_associatedPowerShellDSHandlers.Values);768            }769 770            foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)771            {772                dsHandler.TransportManager.ReadyForDisconnect -= HandleReadyForDisconnect;773                dsHandler.TransportManager.PrepareForConnect();774            }775        }776 777        /// <summary>778        /// Handler of the transport ReadyForDisconnect event.  When all command779        /// transports are ready for disconnect we can start the disconnect process.780        /// </summary>781        /// <param name="sender"></param>782        /// <param name="args"></param>783        private void HandleReadyForDisconnect(object sender, EventArgs args)784        {785            if (sender == null)786            {787                return;788            }789 790            BaseClientCommandTransportManager bcmdTM = (BaseClientCommandTransportManager)sender;791 792            lock (_associationSyncObject)793            {794                // Ignore extra event calls after disconnect is started.795                if (_preparingForDisconnectList == null)796                {797                    return;798                }799 800                _preparingForDisconnectList.Remove(bcmdTM);801 802                if (_preparingForDisconnectList.Count == 0)803                {804                    _preparingForDisconnectList = null;805 806                    // Start the asynchronous disconnect on a worker thread because we don't know807                    // what thread this callback is made from.  If it was made from a transport808                    // callback event then a deadlock may occur when DisconnectAsync is called on809                    // that same thread.810                    ThreadPool.QueueUserWorkItem(new WaitCallback(StartDisconnectAsync));811                }812            }813        }814 815        /// <summary>816        /// WaitCallback method to start an asynchronous disconnect.817        /// </summary>818        /// <param name="state"></param>819        private void StartDisconnectAsync(object state)820        {821            var remoteSession = RemoteSession;822            try823            {824                remoteSession?.DisconnectAsync();825            }826            catch827            {828                // remoteSession may have already been disposed resulting in unexpected exceptions.829            }830        }831 832        /// <summary>833        /// Forwards robust connection notifications to associated PowerShell clients.834        /// </summary>835        /// <param name="sender"></param>836        /// <param name="e"></param>837        private void HandleRobustConnectionNotification(838            object sender,839            ConnectionStatusEventArgs e)840        {841            List<ClientPowerShellDataStructureHandler> dsHandlers;842            lock (_associationSyncObject)843            {844                dsHandlers = new List<ClientPowerShellDataStructureHandler>(_associatedPowerShellDSHandlers.Values);845            }846 847            foreach (ClientPowerShellDataStructureHandler dsHandler in dsHandlers)848            {849                dsHandler.ProcessRobustConnectionNotification(e);850            }851        }852 853        /// <summary>854        /// Forwards the session create completion event.855        /// </summary>856        /// <param name="sender">Transport sender.</param>857        /// <param name="eventArgs">CreateCompleteEventArgs.</param>858        private void HandleSessionCreateCompleted(object sender, CreateCompleteEventArgs eventArgs)859        {860            SessionCreateCompleted.SafeInvoke<CreateCompleteEventArgs>(this, eventArgs);861        }862 863        #endregion Private Methods864 865        #region Private Members866 867        private readonly Guid _clientRunspacePoolId;868        private readonly object _syncObject = new object();869        private bool _createRunspaceCalled = false;870        private Exception _closingReason;871        private readonly int _minRunspaces;872        private readonly int _maxRunspaces;873        private readonly PSHost _host;874        private readonly PSPrimitiveDictionary _applicationArguments;875 876        private readonly Dictionary<Guid, ClientPowerShellDataStructureHandler> _associatedPowerShellDSHandlers877            = new Dictionary<Guid, ClientPowerShellDataStructureHandler>();878 879        // data structure handlers of all ClientRemotePowerShell which are880        // associated with this runspace pool881        private readonly object _associationSyncObject = new object();882        // object to synchronize operations to above883        private readonly BaseClientSessionTransportManager _transportManager;884        // session transport manager associated with this runspace885 886        private List<BaseClientCommandTransportManager> _preparingForDisconnectList;887 888        #endregion Private Members889 890        #region Internal Properties891 892        /// <summary>893        /// The remote session associated with this runspace pool894        /// data structure handler.895        /// </summary>896        internal ClientRemoteSession RemoteSession { get; private set; }897 898        /// <summary>899        /// Transport manager used by this data structure handler.900        /// </summary>901        internal BaseClientSessionTransportManager TransportManager902        {903            get904            {905                if (RemoteSession != null)906                {907                    return RemoteSession.SessionDataStructureHandler.TransportManager;908                }909                else910                {911                    return null;912                }913            }914        }915 916        /// <summary>917        /// Returns robust connection maximum retry time in milliseconds, if supported918        /// by underlying transport manager.919        /// </summary>920        internal int MaxRetryConnectionTime921        {922            get923            {924                if (_transportManager != null &&925                    _transportManager is WSManClientSessionTransportManager)926                {927                    return ((WSManClientSessionTransportManager)(_transportManager)).MaxRetryConnectionTime;928                }929 930                return 0;931            }932        }933 934        /// <summary>935        /// Indicates whether the currently connected runspace endpoint supports936        /// disconnect/connect semantics.937        /// </summary>938        internal bool EndpointSupportsDisconnect939        {940            get941            {942                WSManClientSessionTransportManager wsmanTransportManager = _transportManager as WSManClientSessionTransportManager;943                return wsmanTransportManager != null && wsmanTransportManager.SupportsDisconnect;944            }945        }946 947        #endregion Internal Properties948 949        #region IDisposable950 951        /// <summary>952        /// Public interface for dispose.953        /// </summary>954        public void Dispose()955        {956            Dispose(true);957 958            GC.SuppressFinalize(this);959        }960 961        /// <summary>962        /// Release all resources.963        /// </summary>964        /// <param name="disposing">If true, release all managed resources.</param>965        public void Dispose(bool disposing)966        {967            if (disposing)968            {969                if (RemoteSession != null)970                {971                    ((ClientRemoteSessionImpl)RemoteSession).Dispose();972                    RemoteSession = null;973                }974            }975        }976 977        #endregion IDisposable978    }979 980    /// <summary>981    /// Base class for ClientPowerShellDataStructureHandler to handle all982    /// references.983    /// </summary>984    internal sealed class ClientPowerShellDataStructureHandler985    {986        #region Data Structure Handler events987 988        /// <summary>989        /// This event is raised when the state of associated990        /// powershell is terminal and the runspace pool has991        /// to detach the association.992        /// </summary>993        internal event EventHandler RemoveAssociation;994 995        /// <summary>996        /// This event is raised when a state information object997        /// is received from the server.998        /// </summary>999        internal event EventHandler<RemoteDataEventArgs<PSInvocationStateInfo>> InvocationStateInfoReceived;1000 1001        /// <summary>1002        /// This event is raised when an output object is received1003        /// from the server.1004        /// </summary>1005        internal event EventHandler<RemoteDataEventArgs<object>> OutputReceived;1006 1007        /// <summary>1008        /// This event is raised when an error record is received1009        /// from the server.1010        /// </summary>1011        internal event EventHandler<RemoteDataEventArgs<ErrorRecord>> ErrorReceived;1012 1013        /// <summary>1014        /// This event is raised when an informational message -1015        /// debug, verbose, warning, progress is received from1016        /// the server.1017        /// </summary>1018        internal event EventHandler<RemoteDataEventArgs<InformationalMessage>> InformationalMessageReceived;1019 1020        /// <summary>1021        /// This event is raised when a host call is targeted to the1022        /// powershell.1023        /// </summary>1024        internal event EventHandler<RemoteDataEventArgs<RemoteHostCall>> HostCallReceived;1025 1026        /// <summary>1027        /// This event is raised when a runspace pool data structure handler notifies an1028        /// associated powershell data structure handler that its closed.1029        /// </summary>1030        internal event EventHandler<RemoteDataEventArgs<Exception>> ClosedNotificationFromRunspacePool;1031 1032        /// <summary>1033        /// Event that is raised when a remote connection is successfully closed. The event is raised1034        /// from a WSMan transport thread. Since this thread can hold on to a HTTP1035        /// connection, the event handler should complete processing as fast as possible.1036        /// Importantly the event handler should not generate any call that results in a1037        /// user request like host.ReadLine().1038        ///1039        /// Errors (occurred during connection attempt) are reported through WSManTransportErrorOccured1040        /// event.1041        /// </summary>1042        /// <remarks>1043        /// The eventhandler should make sure not to throw any exceptions.1044        /// </remarks>1045        internal event EventHandler<EventArgs> CloseCompleted;1046 1047        /// <summary>1048        /// This event is raised when a runspace pool data structure handler notifies an1049        /// associated powershell data structure handler that its broken.1050        /// </summary>1051        internal event EventHandler<RemoteDataEventArgs<Exception>> BrokenNotificationFromRunspacePool;1052 1053        /// <summary>1054        /// This event is raised when reconnect async operation on the associated powershell/pipeline instance is completed.1055        /// </summary>1056        internal event EventHandler<RemoteDataEventArgs<Exception>> ReconnectCompleted;1057 1058        /// <summary>1059        /// This event is raised when connect async operation on the associated powershell/pipeline instance is completed.1060        /// </summary>1061        internal event EventHandler<RemoteDataEventArgs<Exception>> ConnectCompleted;1062 1063        /// <summary>1064        /// This event is raised when a Robust Connection layer notification is available.1065        /// </summary>1066        internal event EventHandler<ConnectionStatusEventArgs> RobustConnectionNotification;1067 1068        #endregion Data Structure Handler events1069 1070        #region Data Structure Handler Methods1071 1072        /// <summary>1073        /// Start the command operation.1074        /// </summary>1075        internal void Start(ClientRemoteSessionDSHandlerStateMachine stateMachine, bool inDisconnectMode)1076        {1077            // Add all callbacks to transport manager.1078            SetupTransportManager(inDisconnectMode);1079            TransportManager.CreateAsync();1080        }1081 1082        private void HandleDelayStreamRequestProcessed(object sender, EventArgs e)1083        {1084            // client's request to start pipeline in disconnected mode has been successfully processed1085            ProcessDisconnect(null);1086        }1087 1088        internal void HandleReconnectCompleted(object sender, EventArgs args)1089        {1090            int currentState = Interlocked.CompareExchange(ref _connectionState, (int)connectionStates.Connected, (int)connectionStates.Reconnecting);1091 1092            ReconnectCompleted.SafeInvoke(this, new RemoteDataEventArgs<Exception>(null));1093            return;1094        }1095 1096        internal void HandleConnectCompleted(object sender, EventArgs args)1097        {1098            int currentState = Interlocked.CompareExchange(ref _connectionState, (int)connectionStates.Connected, (int)connectionStates.Connecting);1099 1100            ConnectCompleted.SafeInvoke(this, new RemoteDataEventArgs<Exception>(null));1101            return;1102        }1103 1104        /// <summary>1105        /// Handler which handles transport errors.1106        /// </summary>1107        /// <param name="sender"></param>1108        /// <param name="e"></param>1109        internal void HandleTransportError(object sender, TransportErrorOccuredEventArgs e)1110        {1111            // notify associated powershell about the error and close transport manager1112            PSInvocationStateInfo stateInfo = new PSInvocationStateInfo(PSInvocationState.Failed, e.Exception);1113            InvocationStateInfoReceived.SafeInvoke(this, new RemoteDataEventArgs<PSInvocationStateInfo>(stateInfo));1114 1115            // The handler to InvocationStateInfoReceived would have already1116            // closed the connection. No need to do it here again1117        }1118 1119        /// <summary>1120        /// Send a stop powershell message to the server.1121        /// </summary>1122        internal void SendStopPowerShellMessage()1123        {1124            TransportManager.CryptoHelper.CompleteKeyExchange();1125            TransportManager.SendStopSignal();1126        }1127 1128        /// <summary>1129        /// Event that gets raised when stop signal is completed.1130        /// </summary>1131        /// <param name="sender"></param>1132        /// <param name="e"></param>1133        private void OnSignalCompleted(object sender, EventArgs e)1134        {1135            // Raise stopped event locally...By the time this event1136            // is raised, the remote server would have sent state changed info.1137            // A bad server may not send appropriate sate info, in which case we1138            // fail safely1139            PSRemotingDataStructureException exception = new PSRemotingDataStructureException(1140                RemotingErrorIdStrings.PipelineStopped);1141            InvocationStateInfoReceived.SafeInvoke(this,1142                new RemoteDataEventArgs<PSInvocationStateInfo>(1143                    new PSInvocationStateInfo(PSInvocationState.Stopped, exception)));1144        }1145 1146        /// <summary>1147        /// Send the host response to the server.1148        /// </summary>1149        /// <param name="hostResponse">Host response to send.</param>1150        internal void SendHostResponseToServer(RemoteHostResponse hostResponse)1151        {1152            RemoteDataObject<PSObject> dataToBeSent =1153                RemoteDataObject<PSObject>.CreateFrom(RemotingDestination.Server,1154                RemotingDataType.RemotePowerShellHostResponseData,1155                _clientRunspacePoolId,1156                _clientPowerShellId,1157                hostResponse.Encode());1158 1159            TransportManager.DataToBeSentCollection.Add<PSObject>(dataToBeSent,1160                DataPriorityType.PromptResponse);1161        }1162 1163        /// <summary>1164        /// Attach the specified data collection as input1165        /// to the remote powershell.1166        /// </summary>1167        /// <param name="inputstream"></param>1168        internal void SendInput(ObjectStreamBase inputstream)1169        {1170            if (!inputstream.IsOpen && inputstream.Count == 0)1171            {1172                // there is no input, send an end of input1173                // message1174                lock (_inputSyncObject)1175                {1176                    // send input closed information to server1177                    SendDataAsync(RemotingEncoder.GeneratePowerShellInputEnd(1178                        _clientRunspacePoolId, _clientPowerShellId));1179                }1180            }1181            else1182            {1183                // its possible that in client input data is written in a thread1184                // other than the current thread. Since we want to write input1185                // to the server in the order in which it was received, this1186                // operation of writing to the server need to be synced1187                // Also we need to ensure that all the data currently available1188                // for enumeration are written out before any newly added data1189                // is written. Hence the lock is made even before the handler is1190                // registered1191                lock (_inputSyncObject)1192                {1193                    inputstream.DataReady += HandleInputDataReady;1194                    WriteInput(inputstream);1195                }1196            }1197        }1198 1199        /// <summary>1200        /// Process the data received from the runspace pool

Showing the first 1,200 of 1635 lines. Download the file for the rest.