internal WSManClientSessionTransportManager(Guid runspacePoolInstanceId, WSManConnectionInfo connectionInfo, PSRemotingCryptoHelper cryptoHelper, string sessionName) : base(runspacePoolInstanceId, cryptoHelper) { this.startMode = WSManTransportManagerUtils.tmStartModes.None; base.CryptoHelper = cryptoHelper; base.dataToBeSent.Fragmentor = base.Fragmentor; this.sessionName = sessionName; base.ReceivedDataCollection.MaximumReceivedDataSize = null; base.ReceivedDataCollection.MaximumReceivedObjectSize = connectionInfo.MaximumReceivedObjectSize; this.onDataAvailableToSendCallback = new System.Management.Automation.Remoting.PrioritySendDataCollection.OnDataAvailableCallback(this.OnDataAvailableCallback); this.Initialize(connectionInfo.ConnectionUri, connectionInfo); }
/// <summary> /// Starts connecting to an existing remote session. This will result in a WSManConnectShellEx WSMan /// async call. Piggy backs available data in input stream as openXml in connect SOAP. /// DSHandler will push negotiation related messages through the open content /// </summary> /// <exception cref="PSRemotingTransportException"> /// WSManConnectShellEx failed. /// </exception> internal override void ConnectAsync() { Dbg.Assert(!isClosed, "object already disposed"); Dbg.Assert(!String.IsNullOrEmpty(ConnectionInfo.ShellUri), "shell uri cannot be null or empty."); ReceivedDataCollection.PrepareForStreamConnect(); // additional content with connect shell call. Negotiation and connect related messages // should be included in payload if (null == _openContent) { DataPriorityType additionalDataType; byte[] additionalData = dataToBeSent.ReadOrRegisterCallback(null, out additionalDataType); if (null != additionalData) { // WSMan expects the data to be in XML format (which is text + xml tags) // so convert byte[] into base64 encoded format string base64EncodedDataInXml = string.Format(CultureInfo.InvariantCulture, "<{0} xmlns=\"{1}\">{2}</{0}>", WSManNativeApi.PS_CONNECT_XML_TAG, WSManNativeApi.PS_XML_NAMESPACE, Convert.ToBase64String(additionalData)); _openContent = new WSManNativeApi.WSManData_ManToUn(base64EncodedDataInXml); } //THERE SHOULD BE NO ADDITIONAL DATA. If there is, it means we are not able to push all initial negotiation related data // as part of Connect SOAP. The connect algorithm is based on this assumption. So bail out. additionalData = dataToBeSent.ReadOrRegisterCallback(null, out additionalDataType); if (additionalData != null) { //Negotiation payload does not fit in ConnectShell. bail out. //Assert for now. should be replaced with raising an exception so upper layers can catch. Dbg.Assert(false, "Negotiation payload does not fit in ConnectShell"); return; } } // Create and store context for this shell operation. This context is used from various callbacks _sessionContextID = GetNextSessionTMHandleId(); AddSessionTransportManager(_sessionContextID, this); //session is implicitly assumed to support disconnect SupportsDisconnect = true; // Create Callback _connectSessionCallback = new WSManNativeApi.WSManShellAsync(new IntPtr(_sessionContextID), s_sessionConnectCallback); lock (syncObject) { if (isClosed) { // the transport is already closed..so no need to connect // anymore. return; } Dbg.Assert(_startMode == WSManTransportManagerUtils.tmStartModes.None, "startMode is not in expected state"); _startMode = WSManTransportManagerUtils.tmStartModes.Connect; int flags = 0; flags |= (ConnectionInfo.OutputBufferingMode == Runspaces.OutputBufferingMode.Block) ? (int)WSManNativeApi.WSManShellFlag.WSMAN_FLAG_SERVER_BUFFERING_MODE_BLOCK : 0; flags |= (ConnectionInfo.OutputBufferingMode == Runspaces.OutputBufferingMode.Drop) ? (int)WSManNativeApi.WSManShellFlag.WSMAN_FLAG_SERVER_BUFFERING_MODE_DROP : 0; WSManNativeApi.WSManConnectShellEx(_wsManSessionHandle, flags, ConnectionInfo.ShellUri, RunspacePoolInstanceId.ToString().ToUpperInvariant(), //wsman is case sensitive wrt shellId. so consistently using upper case IntPtr.Zero, _openContent, _connectSessionCallback, ref _wsManShellOperationHandle); } if (_wsManShellOperationHandle == IntPtr.Zero) { TransportErrorOccuredEventArgs eventargs = WSManTransportManagerUtils.ConstructTransportErrorEventArgs(WSManAPIData.WSManAPIHandle, this, new WSManNativeApi.WSManError(), TransportMethodEnum.ConnectShellEx, RemotingErrorIdStrings.ConnectExFailed, this.ConnectionInfo.ComputerName); ProcessWSManTransportError(eventargs); return; } }
private void StartCreateRetry(object state) { // Begin new session create attempt. _startMode = WSManTransportManagerUtils.tmStartModes.None; CreateAsync(); }
/// <summary> /// Redirect the transport manager to point to a new URI. /// </summary> /// <param name="newUri"> /// Redirect Uri to connect to. /// </param> /// <param name="connectionInfo"> /// Connection info object used for retrieving credential, auth. mechanism etc. /// </param> /// <exception cref="PSInvalidOperationException"> /// 1. Create Session failed with a non-zero error code. /// </exception> internal override void Redirect(Uri newUri, RunspaceConnectionInfo connectionInfo) { CloseSessionAndClearResources(); tracer.WriteLine("Redirecting to URI: {0}", newUri); PSEtwLog.LogAnalyticInformational(PSEventId.URIRedirection, PSOpcode.Connect, PSTask.None, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, RunspacePoolInstanceId.ToString(), newUri.ToString()); Initialize(newUri, (WSManConnectionInfo)connectionInfo); //reset startmode _startMode = WSManTransportManagerUtils.tmStartModes.None; CreateAsync(); }
/// <summary> /// Starts connecting to remote end asynchronously. This will result in a WSManCreateShellEx WSMan /// async call. By the time this call returns, we will have a valid handle, if the operation /// succeeds. Make sure other methods are called only after this method returns. Thread /// synchronization is left to the caller. /// </summary> /// <exception cref="PSRemotingTransportException"> /// WSManCreateShellEx failed. /// </exception> internal override void CreateAsync() { Dbg.Assert(!isClosed, "object already disposed"); Dbg.Assert(!String.IsNullOrEmpty(ConnectionInfo.ShellUri), "shell uri cannot be null or empty."); Dbg.Assert(WSManAPIData != null, "WSManApiData should always be created before session creation."); List<WSManNativeApi.WSManOption> shellOptions = new List<WSManNativeApi.WSManOption>(WSManAPIData.CommonOptionSet); #region SHIM: Redirection code for protocol version if (s_protocolVersionRedirect != null) { string newProtocolVersion = (string)s_protocolVersionRedirect.DynamicInvoke(); shellOptions.Clear(); WSManNativeApi.WSManOption newPrtVOption = new WSManNativeApi.WSManOption(); newPrtVOption.name = RemoteDataNameStrings.PS_STARTUP_PROTOCOL_VERSION_NAME; newPrtVOption.value = newProtocolVersion; newPrtVOption.mustComply = true; shellOptions.Add(newPrtVOption); } #endregion // Pass the WSManConnectionInfo object IdleTimeout value if it is // valid. Otherwise pass the default value that instructs the server // to use its default IdleTimeout value. uint uIdleTimeout = (ConnectionInfo.IdleTimeout > 0) ? (uint)ConnectionInfo.IdleTimeout : UseServerDefaultIdleTimeoutUInt; // startup info WSManNativeApi.WSManShellStartupInfo_ManToUn startupInfo = new WSManNativeApi.WSManShellStartupInfo_ManToUn(WSManAPIData.InputStreamSet, WSManAPIData.OutputStreamSet, uIdleTimeout, _sessionName); // additional content with create shell call. Piggy back first fragment from // the dataToBeSent buffer. if (null == _openContent) { DataPriorityType additionalDataType; byte[] additionalData = dataToBeSent.ReadOrRegisterCallback(null, out additionalDataType); #region SHIM: Redirection code for session data send. bool sendContinue = true; if (s_sessionSendRedirect != null) { object[] arguments = new object[2] { null, additionalData }; sendContinue = (bool)s_sessionSendRedirect.DynamicInvoke(arguments); additionalData = (byte[])arguments[0]; } if (!sendContinue) return; #endregion if (null != additionalData) { // WSMan expects the data to be in XML format (which is text + xml tags) // so convert byte[] into base64 encoded format string base64EncodedDataInXml = string.Format(CultureInfo.InvariantCulture, "<{0} xmlns=\"{1}\">{2}</{0}>", WSManNativeApi.PS_CREATION_XML_TAG, WSManNativeApi.PS_XML_NAMESPACE, Convert.ToBase64String(additionalData)); _openContent = new WSManNativeApi.WSManData_ManToUn(base64EncodedDataInXml); } } // Create the session context information only once. CreateAsync() can be called multiple // times by RetrySessionCreation for flaky networks. if (_sessionContextID == 0) { // Create and store context for this shell operation. This context is used from various callbacks _sessionContextID = GetNextSessionTMHandleId(); AddSessionTransportManager(_sessionContextID, this); // Create Callback _createSessionCallback = new WSManNativeApi.WSManShellAsync(new IntPtr(_sessionContextID), s_sessionCreateCallback); _createSessionCallbackGCHandle = GCHandle.Alloc(_createSessionCallback); } PSEtwLog.LogAnalyticInformational(PSEventId.WSManCreateShell, PSOpcode.Connect, PSTask.CreateRunspace, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, RunspacePoolInstanceId.ToString()); try { lock (syncObject) { if (isClosed) { // the transport is already closed..so no need to create a connection // anymore. return; } Dbg.Assert(_startMode == WSManTransportManagerUtils.tmStartModes.None, "startMode is not in expected state"); _startMode = WSManTransportManagerUtils.tmStartModes.Create; if (_noMachineProfile) { WSManNativeApi.WSManOption noProfile = new WSManNativeApi.WSManOption(); noProfile.name = WSManNativeApi.NoProfile; noProfile.mustComply = true; noProfile.value = "1"; shellOptions.Add(noProfile); } int flags = _noCompression ? (int)WSManNativeApi.WSManShellFlag.WSMAN_FLAG_NO_COMPRESSION : 0; flags |= (ConnectionInfo.OutputBufferingMode == Runspaces.OutputBufferingMode.Block) ? (int)WSManNativeApi.WSManShellFlag.WSMAN_FLAG_SERVER_BUFFERING_MODE_BLOCK : 0; flags |= (ConnectionInfo.OutputBufferingMode == Runspaces.OutputBufferingMode.Drop) ? (int)WSManNativeApi.WSManShellFlag.WSMAN_FLAG_SERVER_BUFFERING_MODE_DROP : 0; using (WSManNativeApi.WSManOptionSet optionSet = new WSManNativeApi.WSManOptionSet(shellOptions.ToArray())) { WSManNativeApi.WSManCreateShellEx(_wsManSessionHandle, flags, ConnectionInfo.ShellUri, RunspacePoolInstanceId.ToString().ToUpperInvariant(), startupInfo, optionSet, _openContent, _createSessionCallback, ref _wsManShellOperationHandle); } } if (_wsManShellOperationHandle == IntPtr.Zero) { TransportErrorOccuredEventArgs eventargs = WSManTransportManagerUtils.ConstructTransportErrorEventArgs(WSManAPIData.WSManAPIHandle, this, new WSManNativeApi.WSManError(), TransportMethodEnum.CreateShellEx, RemotingErrorIdStrings.ConnectExFailed, this.ConnectionInfo.ComputerName); ProcessWSManTransportError(eventargs); return; } } finally { startupInfo.Dispose(); } }
internal override void CreateAsync() { List<WSManNativeApi.WSManOption> list = new List<WSManNativeApi.WSManOption>(wsManApiStaticData.CommonOptionSet); if (protocolVersionRedirect != null) { string str = (string) protocolVersionRedirect.DynamicInvoke(new object[0]); list.Clear(); WSManNativeApi.WSManOption item = new WSManNativeApi.WSManOption { name = "protocolversion", value = str, mustComply = true }; list.Add(item); } int serverIdleTimeOut = (this._connectionInfo.IdleTimeout > 0) ? ((int) this._connectionInfo.IdleTimeout) : int.MaxValue; WSManNativeApi.WSManShellStartupInfo startupInfo = new WSManNativeApi.WSManShellStartupInfo(wsManApiStaticData.InputStreamSet, wsManApiStaticData.OutputStreamSet, serverIdleTimeOut, this.sessionName); if (this.openContent == null) { DataPriorityType type; byte[] inArray = base.dataToBeSent.ReadOrRegisterCallback(null, out type); bool flag = true; if (sessionSendRedirect != null) { object[] objArray2 = new object[2]; objArray2[1] = inArray; object[] objArray = objArray2; flag = (bool) sessionSendRedirect.DynamicInvoke(objArray); inArray = (byte[]) objArray[0]; } if (!flag) { return; } if (inArray != null) { string data = string.Format(CultureInfo.InvariantCulture, "<{0} xmlns=\"{1}\">{2}</{0}>", new object[] { "creationXml", "http://schemas.microsoft.com/powershell", Convert.ToBase64String(inArray, Base64FormattingOptions.None) }); this.openContent = new WSManNativeApi.WSManData(data); } } this.sessionContextID = GetNextSessionTMHandleId(); AddSessionTransportManager(this.sessionContextID, this); PSEtwLog.LogAnalyticInformational(PSEventId.WSManCreateShell, PSOpcode.Connect, PSTask.CreateRunspace, PSKeyword.Transport | PSKeyword.UseAlwaysAnalytic, new object[] { base.RunspacePoolInstanceId.ToString() }); this.createSessionCallback = new WSManNativeApi.WSManShellAsync(new IntPtr(this.sessionContextID), sessionCreateCallback); this.createSessionCallbackGCHandle = GCHandle.Alloc(this.createSessionCallback); try { lock (base.syncObject) { if (base.isClosed) { return; } this.startMode = WSManTransportManagerUtils.tmStartModes.Create; if (this.noMachineProfile) { WSManNativeApi.WSManOption option2 = new WSManNativeApi.WSManOption { name = "WINRS_NOPROFILE", mustComply = true, value = "1" }; list.Add(option2); } int flags = this.noCompression ? 1 : 0; flags |= (this._connectionInfo.OutputBufferingMode == OutputBufferingMode.Block) ? 8 : 0; flags |= (this._connectionInfo.OutputBufferingMode == OutputBufferingMode.Drop) ? 4 : 0; using (WSManNativeApi.WSManOptionSet set = new WSManNativeApi.WSManOptionSet(list.ToArray())) { WSManNativeApi.WSManCreateShellEx(this.wsManSessionHandle, flags, this._connectionInfo.ShellUri, base.RunspacePoolInstanceId.ToString().ToUpper(CultureInfo.InvariantCulture), startupInfo, set, this.openContent, (IntPtr) this.createSessionCallback, ref this.wsManShellOperationHandle); } } if (this.wsManShellOperationHandle == IntPtr.Zero) { TransportErrorOccuredEventArgs eventArgs = WSManTransportManagerUtils.ConstructTransportErrorEventArgs(wsManApiStaticData.WSManAPIHandle, this, new WSManNativeApi.WSManError(), TransportMethodEnum.CreateShellEx, RemotingErrorIdStrings.ConnectExFailed, new object[] { this.ConnectionInfo.ComputerName }); this.ProcessWSManTransportError(eventArgs); } } finally { startupInfo.Dispose(); } }
internal override void ConnectAsync() { base.ReceivedDataCollection.PrepareForStreamConnect(); if (this.openContent == null) { DataPriorityType type; byte[] inArray = base.dataToBeSent.ReadOrRegisterCallback(null, out type); if (inArray != null) { string data = string.Format(CultureInfo.InvariantCulture, "<{0} xmlns=\"{1}\">{2}</{0}>", new object[] { "connectXml", "http://schemas.microsoft.com/powershell", Convert.ToBase64String(inArray, Base64FormattingOptions.None) }); this.openContent = new WSManNativeApi.WSManData(data); } if (base.dataToBeSent.ReadOrRegisterCallback(null, out type) != null) { return; } } this.sessionContextID = GetNextSessionTMHandleId(); AddSessionTransportManager(this.sessionContextID, this); this.supportsDisconnect = true; this.connectSessionCallback = new WSManNativeApi.WSManShellAsync(new IntPtr(this.sessionContextID), sessionConnectCallback); lock (base.syncObject) { if (base.isClosed) { return; } this.startMode = WSManTransportManagerUtils.tmStartModes.Connect; int flags = 0; flags |= (this._connectionInfo.OutputBufferingMode == OutputBufferingMode.Block) ? 8 : 0; flags |= (this._connectionInfo.OutputBufferingMode == OutputBufferingMode.Drop) ? 4 : 0; WSManNativeApi.WSManConnectShellEx(this.wsManSessionHandle, flags, this._connectionInfo.ShellUri, base.RunspacePoolInstanceId.ToString().ToUpper(CultureInfo.InvariantCulture), IntPtr.Zero, (IntPtr) this.openContent, (IntPtr) this.connectSessionCallback, ref this.wsManShellOperationHandle); } if (this.wsManShellOperationHandle == IntPtr.Zero) { TransportErrorOccuredEventArgs eventArgs = WSManTransportManagerUtils.ConstructTransportErrorEventArgs(wsManApiStaticData.WSManAPIHandle, this, new WSManNativeApi.WSManError(), TransportMethodEnum.ConnectShellEx, RemotingErrorIdStrings.ConnectExFailed, new object[] { this.ConnectionInfo.ComputerName }); this.ProcessWSManTransportError(eventArgs); } }