internal WSManPluginShellSession( WSManNativeApi.WSManPluginRequest creationRequestDetails, WSManPluginServerTransportManager trnsprtMgr, ServerRemoteSession remoteSession, WSManPluginOperationShutdownContext shutDownContext) : base(creationRequestDetails, trnsprtMgr) { _remoteSession = remoteSession; _remoteSession.Closed += new EventHandler <RemoteSessionStateMachineEventArgs>(this.HandleServerRemoteSessionClosed); _activeCommandSessions = new Dictionary <IntPtr, WSManPluginCommandSession>(); this.shellSyncObject = new System.Object(); this.shutDownContext = shutDownContext; }
/// <summary> /// Callback used to register with thread pool to notify when a plugin operation shuts down. /// Conforms to: /// public delegate void WaitOrTimerCallback( Object state, bool timedOut ) /// </summary> /// <param name="operationContext">PVOID.</param> /// <param name="timedOut">BOOLEAN.</param> /// <returns></returns> public static void PSPluginOperationShutdownCallback( object operationContext, bool timedOut) { if (operationContext == null) { return; } WSManPluginOperationShutdownContext context = (WSManPluginOperationShutdownContext)operationContext; context.isShuttingDown = true; WSManPluginInstance.PerformCloseOperation(context); }
internal override void CloseOperation( WSManPluginOperationShutdownContext context, Exception reasonForClose) { // let command sessions to close. lock (cmdSyncObject) { if (isClosed) { return; } if (!context.isReceiveOperation) { isClosed = true; } } WSManPluginInstance.SetThreadProperties(creationRequestDetails); bool isRcvOp = context.isReceiveOperation; // only one thread will be here. bool isRcvOpShuttingDown = (context.isShuttingDown) && (context.isReceiveOperation) && (context.commandContext == creationRequestDetails.unmanagedHandle); bool isCmdShuttingDown = (context.isShuttingDown) && (!context.isReceiveOperation) && (context.commandContext == creationRequestDetails.unmanagedHandle); // close the pending send operation if any ReportSendOperationComplete(); // close the shell's transport manager first..so we wont send data. transportMgr.DoClose(isRcvOpShuttingDown, reasonForClose); if (!isRcvOp) { // raise session closed event and let dependent code to release resources. // null check is not performed here because Managed C++ will take care of this. base.SafeInvokeSessionClosed(creationRequestDetails.unmanagedHandle, EventArgs.Empty); // Send Operation Complete to WSMan service WSManPluginInstance.ReportWSManOperationComplete(creationRequestDetails, reasonForClose); // let base class release its resources this.Close(isCmdShuttingDown); } }
internal override void CloseOperation( WSManPluginOperationShutdownContext context, Exception reasonForClose) { // let command sessions to close. lock (shellSyncObject) { if (isClosed) { return; } if (!context.isReceiveOperation) { isClosed = true; } } WSManPluginInstance.SetThreadProperties(creationRequestDetails); bool isRcvOpShuttingDown = (context.isShuttingDown) && (context.isReceiveOperation); bool isRcvOp = context.isReceiveOperation; bool isShuttingDown = context.isShuttingDown; // close the pending send operation if any ReportSendOperationComplete(); // close the shell's transport manager after commands handled the operation transportMgr.DoClose(isRcvOpShuttingDown, reasonForClose); if (!isRcvOp) { // Initiate close on the active command sessions and then clear the internal // Command Session dictionary CloseAndClearCommandSessions(reasonForClose); // raise session closed event and let dependent code to release resources. // null check is not performed here because the handler will take care of this. base.SafeInvokeSessionClosed(creationRequestDetails.unmanagedHandle, EventArgs.Empty); // Send Operation Complete to WSMan service WSManPluginInstance.ReportWSManOperationComplete(creationRequestDetails, reasonForClose); // let base class release its resources base.Close(isShuttingDown); } // TODO: Do this.Dispose(); here? }
// Closes the command and clears associated resources internal void CloseCommandOperation( WSManPluginOperationShutdownContext context) { WSManPluginCommandSession mgdCmdSession = GetCommandSession(context.commandContext); if (null == mgdCmdSession) { // this should never be the case. this will protect the service. return; } // update the internal data store only if this is not receive operation. if (!context.isReceiveOperation) { DeleteFromActiveCmdSessions(mgdCmdSession.creationRequestDetails.unmanagedHandle); } mgdCmdSession.CloseOperation(context, null); }
internal bool EnableSessionToSendDataToClient( WSManNativeApi.WSManPluginRequest requestDetails, int flags, WSManNativeApi.WSManStreamIDSet_UnToMan streamSet, WSManPluginOperationShutdownContext ctxtToReport) { if (true == isClosed) { WSManPluginInstance.ReportWSManOperationComplete(requestDetails, lastErrorReported); return(false); } if ((null == streamSet) || (1 != streamSet.streamIDsCount)) { // only "stdout" is the supported output stream. WSManPluginInstance.ReportOperationComplete( requestDetails, WSManPluginErrorCodes.InvalidOutputStream, StringUtil.Format( RemotingErrorIdStrings.WSManPluginInvalidOutputStream, WSManPluginConstants.SupportedOutputStream)); return(false); } if (!String.Equals(streamSet.streamIDs[0], WSManPluginConstants.SupportedOutputStream, StringComparison.Ordinal)) { // only "stdout" is the supported output stream. WSManPluginInstance.ReportOperationComplete( requestDetails, WSManPluginErrorCodes.InvalidOutputStream, StringUtil.Format( RemotingErrorIdStrings.WSManPluginInvalidOutputStream, WSManPluginConstants.SupportedOutputStream)); return(false); } return(transportMgr.EnableTransportManagerSendDataToClient(requestDetails, ctxtToReport)); }
internal abstract void CloseOperation(WSManPluginOperationShutdownContext context, Exception reasonForClose);
internal void DoClose( bool isShuttingDown, Exception reasonForClose) { if (_isClosed) { return; } lock (_syncObject) { if (_isClosed) { return; } _isClosed = true; _lastErrorReported = reasonForClose; if (!_isRequestPending) { // release threads blocked on the sending data to client if any _waitHandle.Set(); } } // only one thread will reach here // let everyone know that we are about to close try { RaiseClosingEvent(); foreach (var cmdTransportKvp in _activeCmdTransportManagers) { cmdTransportKvp.Value.Close(reasonForClose); } _activeCmdTransportManagers.Clear(); if (_registeredShutDownWaitHandle != null) { // This will not wait for the callback to complete. _registeredShutDownWaitHandle.Unregister(null); _registeredShutDownWaitHandle = null; } // Delete the context only if isShuttingDown != true. isShuttingDown will // be true only when the method is called from RegisterWaitForSingleObject // handler..in which case the context will be freed from the callback. if (_shutDownContext != null) { _shutDownContext = null; } // This might happen when client did not send a receive request // but the server is closing if (_requestDetails != null) { // Notify that no more data is being sent on this transport. WSManNativeApi.WSManPluginReceiveResult( _requestDetails.unmanagedHandle, (int)WSManNativeApi.WSManFlagReceive.WSMAN_FLAG_RECEIVE_RESULT_NO_MORE_DATA, WSManPluginConstants.SupportedOutputStream, IntPtr.Zero, WSManNativeApi.WSMAN_COMMAND_STATE_DONE, 0); WSManPluginInstance.ReportWSManOperationComplete(_requestDetails, reasonForClose); // We should not use request details again after reporting operation complete // so releasing the resource. Remember not to free this memory as this memory // is allocated and owned by WSMan. _requestDetails = null; } } finally { // dispose resources _waitHandle.Dispose(); } }
internal bool EnableTransportManagerSendDataToClient( WSManNativeApi.WSManPluginRequest requestDetails, WSManPluginOperationShutdownContext ctxtToReport) { _shutDownContext = ctxtToReport; bool isRegisterWaitForSingleObjectSucceeded = true; lock (_syncObject) { if (_isRequestPending) { // if a request is already pending..ignore this. WSManPluginInstance.ReportWSManOperationComplete( requestDetails, WSManPluginErrorCodes.NoError); return(false); } if (_isClosed) { WSManPluginInstance.ReportWSManOperationComplete(requestDetails, _lastErrorReported); return(false); } _isRequestPending = true; _requestDetails = requestDetails; if (Platform.IsWindows) { // Wrap the provided handle so it can be passed to the registration function SafeWaitHandle safeWaitHandle = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); eventWaitHandle.SafeWaitHandle = safeWaitHandle; _registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject( eventWaitHandle, new WaitOrTimerCallback(WSManPluginManagedEntryWrapper.PSPluginOperationShutdownCallback), _shutDownContext, -1, // INFINITE true); // TODO: Do I need to worry not being able to set missing WT_TRANSFER_IMPERSONATION? if (_registeredShutDownWaitHandle == null) { isRegisterWaitForSingleObjectSucceeded = false; } } // release thread waiting to send data to the client. _waitHandle.Set(); } if (!isRegisterWaitForSingleObjectSucceeded) { WSManPluginInstance.PerformCloseOperation(ctxtToReport); WSManPluginInstance.ReportOperationComplete( requestDetails, WSManPluginErrorCodes.ShutdownRegistrationFailed, StringUtil.Format( RemotingErrorIdStrings.WSManPluginShutdownRegistrationFailed)); return(false); } return(true); }