/// <summary> /// This method sends the server side capability negotiation packet to the client. /// </summary> internal override void SendNegotiationAsync() { RemoteSessionCapability serverCapability = _session.Context.ServerCapability; RemoteDataObject data = RemotingEncoder.GenerateServerSessionCapability(serverCapability, Guid.Empty); RemoteSessionStateMachineEventArgs negotiationSendCompletedArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationSendCompleted); _stateMachine.RaiseEvent(negotiationSendCompletedArg); RemoteDataObject<PSObject> dataToBeSent = RemoteDataObject<PSObject>.CreateFrom( data.Destination, data.DataType, data.RunspacePoolId, data.PowerShellId, (PSObject)data.Data); // send data to client..flush is not true as we expect to send state changed // information (from runspace creation) _transportManager.SendDataToClient<PSObject>(dataToBeSent, false); }
/// <summary> /// Processes events in the queue. If there are no /// more events to process, then sets eventsInProcess /// variable to false. This will ensure that another /// thread which raises an event can then take control /// of processing the events. /// </summary> private void ProcessEvents() { RemoteSessionStateMachineEventArgs eventArgs = null; do { lock (_syncObject) { if (_processPendingEventsQueue.Count == 0) { _eventsInProcess = false; break; } eventArgs = _processPendingEventsQueue.Dequeue(); } try { RaiseEventPrivate(eventArgs); } catch (Exception ex) { HandleFatalError(ex); } try { RaiseStateMachineEvents(); } catch (Exception ex) { HandleFatalError(ex); } } while (_eventsInProcess); }
/// <summary> /// This method is used by all classes to raise a FSM event. /// The method will queue the event. The event queue will be handled in /// a thread safe manner by a single dedicated thread. /// </summary> /// <param name="arg"> /// This parameter contains the event to be raised. /// </param> /// <param name="clearQueuedEvents"> /// optional bool indicating whether to clear currently queued events /// </param> /// <exception cref="ArgumentNullException"> /// If the parameter is null. /// </exception> internal void RaiseEvent(RemoteSessionStateMachineEventArgs arg, bool clearQueuedEvents = false) { lock (_syncObject) { s_trace.WriteLine("Event received : {0} for {1}", arg.StateEvent, _id); if (clearQueuedEvents) { _processPendingEventsQueue.Clear(); } _processPendingEventsQueue.Enqueue(arg); if (!_eventsInProcess) { _eventsInProcess = true; } else { return; } } ProcessEvents(); }
/// <summary> /// This is the handler for NegotiationPending event. /// NegotiationPending state can be in reached in the following cases /// 1. From Idle to NegotiationPending (during startup) /// 2. From Negotiation(Response)Sent to NegotiationPending. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoNegotiationPending(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert((_state == RemoteSessionState.Idle) || (_state == RemoteSessionState.NegotiationSent), "DoNegotiationPending can only occur when the state is Idle or NegotiationSent."); SetState(RemoteSessionState.NegotiationPending, null); } }
/// <summary> /// Helper method used by dependents to figure out if the RaiseEvent /// method can be short-circuited. This will be useful in cases where /// the dependent code wants to take action immediately instead of /// going through state machine. /// </summary> /// <param name="arg"></param> internal bool CanByPassRaiseEvent(RemoteSessionStateMachineEventArgs arg) { if (arg.StateEvent == RemoteSessionEvent.MessageReceived) { if (_state == RemoteSessionState.Established || _state == RemoteSessionState.EstablishedAndKeySent || //server session will never be in this state.. TODO- remove this _state == RemoteSessionState.EstablishedAndKeyReceived || _state == RemoteSessionState.EstablishedAndKeyExchanged) { return true; } } return false; }
/// <summary> /// This is the private version of raising a FSM event. /// It can only be called by the dedicated thread that processes the event queue. /// It calls the event handler /// in the right position of the event handling matrix. /// </summary> /// <param name="fsmEventArg"> /// The parameter contains the actual FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter is null. /// </exception> private void RaiseEventPrivate(RemoteSessionStateMachineEventArgs fsmEventArg) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } EventHandler<RemoteSessionStateMachineEventArgs> handler = _stateMachineHandle[(int)_state, (int)fsmEventArg.StateEvent]; if (handler != null) { s_trace.WriteLine("Before calling state machine event handler: state = {0}, event = {1}", _state, fsmEventArg.StateEvent); handler(this, fsmEventArg); s_trace.WriteLine("After calling state machine event handler: state = {0}, event = {1}", _state, fsmEventArg.StateEvent); } }
private void SetStateHandler(object sender, RemoteSessionStateMachineEventArgs eventArgs) { switch (eventArgs.StateEvent) { case RemoteSessionEvent.NegotiationSendCompleted: this.SetState(RemoteSessionState.NegotiationSent, null); return; case RemoteSessionEvent.NegotiationReceived: if (eventArgs.RemoteSessionCapability == null) { throw PSTraceSource.NewArgumentException("eventArgs"); } this.SetState(RemoteSessionState.NegotiationReceived, null); return; case RemoteSessionEvent.NegotiationCompleted: this.SetState(RemoteSessionState.Established, null); return; case RemoteSessionEvent.NegotiationPending: case RemoteSessionEvent.Close: case RemoteSessionEvent.KeySendFailed: case RemoteSessionEvent.KeyReceiveFailed: case RemoteSessionEvent.KeyRequestFailed: case RemoteSessionEvent.DisconnectStart: case RemoteSessionEvent.ReconnectStart: break; case RemoteSessionEvent.CloseCompleted: this.SetState(RemoteSessionState.Closed, eventArgs.Reason); return; case RemoteSessionEvent.CloseFailed: this.SetState(RemoteSessionState.Closed, eventArgs.Reason); return; case RemoteSessionEvent.ConnectFailed: this.SetState(RemoteSessionState.ClosingConnection, eventArgs.Reason); return; case RemoteSessionEvent.KeySent: if ((this._state != RemoteSessionState.Established) && (this._state != RemoteSessionState.EstablishedAndKeyRequested)) { break; } this.SetState(RemoteSessionState.EstablishedAndKeySent, eventArgs.Reason); this._keyExchangeTimer = new System.Timers.Timer(); this._keyExchangeTimer.AutoReset = false; this._keyExchangeTimer.Elapsed += new ElapsedEventHandler(this.HandleKeyExchangeTimeout); this._keyExchangeTimer.Interval = 180000.0; return; case RemoteSessionEvent.KeyReceived: if (this._state != RemoteSessionState.EstablishedAndKeySent) { break; } if (this._keyExchangeTimer != null) { this._keyExchangeTimer.Enabled = false; this._keyExchangeTimer.Dispose(); this._keyExchangeTimer = null; } this.keyExchanged = true; this.SetState(RemoteSessionState.Established, eventArgs.Reason); if (!this.pendingDisconnect) { break; } this.pendingDisconnect = false; this.DoDisconnect(sender, eventArgs); return; case RemoteSessionEvent.KeyRequested: if (this._state != RemoteSessionState.Established) { break; } this.SetState(RemoteSessionState.EstablishedAndKeyRequested, eventArgs.Reason); return; case RemoteSessionEvent.DisconnectCompleted: if ((this._state != RemoteSessionState.Disconnecting) && (this._state != RemoteSessionState.RCDisconnecting)) { break; } this.SetState(RemoteSessionState.Disconnected, eventArgs.Reason); return; case RemoteSessionEvent.DisconnectFailed: if (this._state != RemoteSessionState.Disconnecting) { break; } this.SetState(RemoteSessionState.Disconnected, eventArgs.Reason); return; case RemoteSessionEvent.ReconnectCompleted: if (this._state == RemoteSessionState.Reconnecting) { this.SetState(RemoteSessionState.Established, eventArgs.Reason); } break; default: return; } }
private void DoFatal(object sender, RemoteSessionStateMachineEventArgs eventArgs) => this.RaiseEvent(new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close, (Exception) new PSRemotingDataStructureException(eventArgs.Reason, PSRemotingErrorId.FatalErrorCausingClose, new object[0])));
/// <summary> /// This is the handler for ConnectFailed event. In this implementation, this should never /// happen. This is because the IO channel is stdin/stdout/stderr redirection. /// Therefore, the connection is a dummy operation. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// If the parameter <paramref name="fsmEventArg"/> does not contain ConnectFailed event. /// </exception> private void DoConnectFailed(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.ConnectFailed, "StateEvent must be ConnectFailed"); if (fsmEventArg.StateEvent != RemoteSessionEvent.ConnectFailed) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } Dbg.Assert(_state == RemoteSessionState.Connecting, "session State must be Connecting"); // This method should not be called in this implementation. throw PSTraceSource.NewInvalidOperationException(); } }
/// <summary> /// This is the handler for CloseFailed event. /// It simply force the new state to be Closed. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoCloseFailed(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.CloseFailed, "StateEvent must be CloseFailed"); RemoteSessionState stateBeforeTransition = _state; SetState(RemoteSessionState.Closed, fsmEventArg.Reason); // ignore CleanAll(); } }
public override void CreateAsync() { RemoteSessionStateMachineEventArgs arg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.CreateSession); base.SessionDataStructureHandler.StateMachine.RaiseEvent(arg, false); }
public override void DisconnectAsync() { RemoteSessionStateMachineEventArgs arg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.DisconnectStart); base.SessionDataStructureHandler.StateMachine.RaiseEvent(arg, false); }
/// <summary> /// This handler method runs the negotiation algorithm. It decides if the negotiation is succesful, /// or fails. /// </summary> /// <param name="sender"></param> /// <param name="negotiationEventArg"> /// This parameter contains the client negotiation capability packet. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="negotiationEventArg"/> is null. /// </exception> private void HandleNegotiationReceived(object sender, RemoteSessionNegotiationEventArgs negotiationEventArg) { if (negotiationEventArg == null) { throw PSTraceSource.NewArgumentNullException("negotiationEventArg"); } try { Context.ClientCapability = negotiationEventArg.RemoteSessionCapability; // This will throw if there is an error running the algorithm RunServerNegotiationAlgorithm(negotiationEventArg.RemoteSessionCapability, false); // Send server's capability to client. RemoteSessionStateMachineEventArgs sendingNegotiationArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationSending); SessionDataStructureHandler.StateMachine.RaiseEvent(sendingNegotiationArg); // if negotiation succeeded change the state to neg. completed. RemoteSessionStateMachineEventArgs negotiationCompletedArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationCompleted); SessionDataStructureHandler.StateMachine.RaiseEvent(negotiationCompletedArg); } catch (PSRemotingDataStructureException dse) { // Before setting to negotiation failed..send servers capability...that // way client can communicate differently if it wants to. RemoteSessionStateMachineEventArgs sendingNegotiationArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationSending); SessionDataStructureHandler.StateMachine.RaiseEvent(sendingNegotiationArg); RemoteSessionStateMachineEventArgs negotiationFailedArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationFailed, dse); SessionDataStructureHandler.StateMachine.RaiseEvent(negotiationFailedArg); } }
/// <summary> /// This handles closing of any resource used by this session. /// Resources used are RunspacePoolDriver, TransportManager. /// </summary> /// <param name="sender"></param> /// <param name="args"></param> private void HandleResourceClosing(object sender, EventArgs args) { RemoteSessionStateMachineEventArgs closeSessionArgs = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close); closeSessionArgs.RemoteData = null; SessionDataStructureHandler.StateMachine.RaiseEvent(closeSessionArgs); }
private void DoDisconnect(object sender, RemoteSessionStateMachineEventArgs arg) { this.SetState(RemoteSessionState.Disconnecting, null); }
internal void DispatchInputQueueData(object sender, RemoteDataEventArgs dataEventArg) { using (ServerRemoteSession._trace.TraceMethod()) { RemoteDataObject <PSObject> remoteDataObject = dataEventArg != null ? dataEventArg.ReceivedData : throw ServerRemoteSession._trace.NewArgumentNullException(nameof(dataEventArg)); RemotingDestination remotingDestination = remoteDataObject != null ? remoteDataObject.Destination : throw ServerRemoteSession._trace.NewArgumentException(nameof(dataEventArg)); if ((remotingDestination & this.MySelf) != this.MySelf) { throw new PSRemotingDataStructureException(PSRemotingErrorId.RemotingDestinationNotForMe, new object[2] { (object)this.MySelf, (object)remotingDestination }); } RemotingTargetInterface targetInterface = remoteDataObject.TargetInterface; RemotingDataType dataType = remoteDataObject.DataType; switch (targetInterface) { case RemotingTargetInterface.Session: switch (dataType) { case RemotingDataType.SessionCapability: this._sessionDSHandler.RaiseDataReceivedEvent(dataEventArg); return; case RemotingDataType.CloseSession: this._sessionDSHandler.RaiseDataReceivedEvent(dataEventArg); return; case RemotingDataType.CreateRunspacePool: RemoteSessionStateMachineEventArgs fsmEventArg1 = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.MessageReceived); if (this.SessionDataStructureHandler.StateMachine.CanByPassRaiseEvent(fsmEventArg1)) { fsmEventArg1.RemoteData = remoteDataObject; this.SessionDataStructureHandler.StateMachine.DoMessageReceived((object)this, fsmEventArg1); return; } this.SessionDataStructureHandler.StateMachine.RaiseEvent(fsmEventArg1); return; case RemotingDataType.PublicKey: this._sessionDSHandler.RaiseDataReceivedEvent(dataEventArg); return; default: return; } case RemotingTargetInterface.RunspacePool: case RemotingTargetInterface.PowerShell: RemoteSessionStateMachineEventArgs fsmEventArg2 = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.MessageReceived); if (this.SessionDataStructureHandler.StateMachine.CanByPassRaiseEvent(fsmEventArg2)) { fsmEventArg2.RemoteData = remoteDataObject; this.SessionDataStructureHandler.StateMachine.DoMessageReceived((object)this, fsmEventArg2); break; } this.SessionDataStructureHandler.StateMachine.RaiseEvent(fsmEventArg2); break; } } }
/// <summary> /// Connects to a existing Remote Session Asynchronously by executing a Connect negotiation algorithm. /// </summary> public override void ConnectAsync() { // Raise the connectsession event in statemachine. This start the process of connection and negotiation to an existing remote session RemoteSessionStateMachineEventArgs startArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.ConnectSession); SessionDataStructureHandler.StateMachine.RaiseEvent(startArg); }
/// <summary> /// This is the handler for NegotiationSending event. /// It sets the new state to be NegotiationSending, and sends the server side /// negotiation packet by queuing it on the output queue. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoNegotiationSending(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.NegotiationSending, "Event must be NegotiationSending"); Dbg.Assert(_state == RemoteSessionState.NegotiationReceived, "State must be NegotiationReceived"); SetState(RemoteSessionState.NegotiationSending, null); _session.SessionDataStructureHandler.SendNegotiationAsync(); }
/// <summary> /// This method contains all the logic for handling the state machine /// for key exchange. All the different scenarios are covered in this /// </summary> /// <param name="sender">sender of this event, unused</param> /// <param name="eventArgs">event args</param> private void DoKeyExchange(object sender, RemoteSessionStateMachineEventArgs eventArgs) { //There are corner cases with disconnect that can result in client receiving outdated key exchange packets //***TODO*** Deal with this on the client side. Key exchange packets should have additional information //that identify the context of negotiation. Just like callId in SetMax and SetMinRunspaces messages Dbg.Assert(_state >= RemoteSessionState.Established, "Key Receving can only be raised after reaching the Established state"); switch (eventArgs.StateEvent) { case RemoteSessionEvent.KeyReceived: { //does the server ever start key exchange process??? This may not be required if (_state == RemoteSessionState.EstablishedAndKeyRequested) { // reset the timer Timer tmp = Interlocked.Exchange(ref _keyExchangeTimer, null); if (tmp != null) { tmp.Dispose(); } } // the key import would have been done // set state accordingly SetState(RemoteSessionState.EstablishedAndKeyReceived, eventArgs.Reason); // you need to send an encrypted session key to the client _session.SendEncryptedSessionKey(); } break; case RemoteSessionEvent.KeySent: { if (_state == RemoteSessionState.EstablishedAndKeyReceived) { // key exchange is now complete SetState(RemoteSessionState.EstablishedAndKeyExchanged, eventArgs.Reason); } } break; case RemoteSessionEvent.KeyRequested: { if ((_state == RemoteSessionState.Established) || (_state == RemoteSessionState.EstablishedAndKeyExchanged)) { // the key has been sent set state accordingly SetState(RemoteSessionState.EstablishedAndKeyRequested, eventArgs.Reason); // start the timer _keyExchangeTimer = new Timer(HandleKeyExchangeTimeout, null, BaseTransportManager.ServerDefaultKeepAliveTimeoutMs, Timeout.Infinite); } } break; case RemoteSessionEvent.KeyReceiveFailed: { if ((_state == RemoteSessionState.Established) || (_state == RemoteSessionState.EstablishedAndKeyExchanged)) { return; } DoClose(this, eventArgs); } break; case RemoteSessionEvent.KeySendFailed: { DoClose(this, eventArgs); } break; } }
/// <summary> /// This is the handler for the NegotiationCompleted event. /// It sets the new state to be Established. It turns off the negotiation timeout timer. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoEstablished(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(_state == RemoteSessionState.NegotiationSent, "State must be NeogtiationReceived"); Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.NegotiationCompleted, "StateEvent must be NegotiationCompleted"); if (fsmEventArg.StateEvent != RemoteSessionEvent.NegotiationCompleted) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } if (_state != RemoteSessionState.NegotiationSent) { throw PSTraceSource.NewInvalidOperationException(); } SetState(RemoteSessionState.Established, null); } }
private void DoDisconnectDuringKeyExchange(object sender, RemoteSessionStateMachineEventArgs arg) { // set flag to indicate Disconnect request queue up _pendingDisconnect = true; }
/// <summary> /// Handle connect event - this is raised when a new client tries to connect to an existing session /// No changes to state. Calls into the session to handle any post connect operations /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"></param> private void DoConnect(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { Dbg.Assert(_state != RemoteSessionState.Idle, "session should not be in idle state when SessionConnect event is queued"); if ((_state != RemoteSessionState.Closed) && (_state != RemoteSessionState.ClosingConnection)) { _session.HandlePostConnect(); } }
internal void DispatchInputQueueData(object sender, RemoteDataEventArgs dataEventArg) { if (dataEventArg == null) { throw PSTraceSource.NewArgumentNullException("dataEventArg"); } RemoteDataObject <PSObject> receivedData = dataEventArg.ReceivedData; if (receivedData == null) { throw PSTraceSource.NewArgumentException("dataEventArg"); } RemotingDestination destination = receivedData.Destination; if ((destination & this.MySelf) != this.MySelf) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.RemotingDestinationNotForMe, new object[] { this.MySelf, destination }); } RemotingTargetInterface targetInterface = receivedData.TargetInterface; RemotingDataType dataType = receivedData.DataType; RemoteSessionStateMachineEventArgs arg = null; switch (targetInterface) { case RemotingTargetInterface.Session: switch (dataType) { case RemotingDataType.SessionCapability: this._sessionDSHandler.RaiseDataReceivedEvent(dataEventArg); return; case RemotingDataType.CloseSession: this._sessionDSHandler.RaiseDataReceivedEvent(dataEventArg); return; case RemotingDataType.CreateRunspacePool: arg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.MessageReceived); if (this.SessionDataStructureHandler.StateMachine.CanByPassRaiseEvent(arg)) { arg.RemoteData = receivedData; this.SessionDataStructureHandler.StateMachine.DoMessageReceived(this, arg); return; } this.SessionDataStructureHandler.StateMachine.RaiseEvent(arg); return; case RemotingDataType.PublicKey: this._sessionDSHandler.RaiseDataReceivedEvent(dataEventArg); return; } return; case RemotingTargetInterface.RunspacePool: case RemotingTargetInterface.PowerShell: arg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.MessageReceived); if (!this.SessionDataStructureHandler.StateMachine.CanByPassRaiseEvent(arg)) { this.SessionDataStructureHandler.StateMachine.RaiseEvent(arg); return; } arg.RemoteData = receivedData; this.SessionDataStructureHandler.StateMachine.DoMessageReceived(this, arg); return; } }
/// <summary> /// This is the handler for NegotiationTimeout event. /// If the connection is already Established, it ignores this event. /// Otherwise, it raises a Close event to trigger a close of the connection. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoNegotiationTimeout(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.NegotiationTimeout, "StateEvent must be NegotiationTimeout"); if (_state == RemoteSessionState.Established) { // ignore return; } RemoteSessionStateMachineEventArgs closeArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close); RaiseEventPrivate(closeArg); } }
private void DoDisconnectDuringKeyExchange(object sender, RemoteSessionStateMachineEventArgs arg) { this.pendingDisconnect = true; }
/// <summary> /// Restores connection to a disconnected remote session. Negotiation has already been performed before /// </summary> public override void ReconnectAsync() { RemoteSessionStateMachineEventArgs startReconnectArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.ReconnectStart); SessionDataStructureHandler.StateMachine.RaiseEvent(startReconnectArg); }
/// <summary> /// Connects to a existing Remote Session Asynchronously by executing a Connect negotiation algorithm /// </summary> public override void ConnectAsync() { //Raise the connectsession event in statemachine. This start the process of connection and negotiation to an existing remote session RemoteSessionStateMachineEventArgs startArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.ConnectSession); SessionDataStructureHandler.StateMachine.RaiseEvent(startArg); }
/// <summary> /// This is the handler for MessageReceived event. It dispatches the data to various components /// that uses the data. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// If the parameter <paramref name="fsmEventArg"/> does not contain remote data. /// </exception> internal void DoMessageReceived(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } if (fsmEventArg.RemoteData == null) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } Dbg.Assert(_state == RemoteSessionState.Established || _state == RemoteSessionState.EstablishedAndKeyExchanged || _state == RemoteSessionState.EstablishedAndKeyReceived || _state == RemoteSessionState.EstablishedAndKeySent, //server session will never be in this state.. TODO- remove this "State must be Established or EstablishedAndKeySent or EstablishedAndKeyReceived or EstablishedAndKeyExchanged"); RemotingTargetInterface targetInterface = fsmEventArg.RemoteData.TargetInterface; RemotingDataType dataType = fsmEventArg.RemoteData.DataType; Guid clientRunspacePoolId; ServerRunspacePoolDriver runspacePoolDriver; //string errorMessage = null; RemoteDataEventArgs remoteDataForSessionArg = null; switch (targetInterface) { case RemotingTargetInterface.Session: { switch (dataType) { // GETBACK case RemotingDataType.CreateRunspacePool: remoteDataForSessionArg = new RemoteDataEventArgs(fsmEventArg.RemoteData); _session.SessionDataStructureHandler.RaiseDataReceivedEvent(remoteDataForSessionArg); break; default: Dbg.Assert(false, "Should never reach here"); break; } } break; case RemotingTargetInterface.RunspacePool: // GETBACK clientRunspacePoolId = fsmEventArg.RemoteData.RunspacePoolId; runspacePoolDriver = _session.GetRunspacePoolDriver(clientRunspacePoolId); if (runspacePoolDriver != null) { runspacePoolDriver.DataStructureHandler.ProcessReceivedData(fsmEventArg.RemoteData); } else { s_trace.WriteLine(@"Server received data for Runspace (id: {0}), but the Runspace cannot be found", clientRunspacePoolId); PSRemotingDataStructureException reasonOfFailure = new PSRemotingDataStructureException(RemotingErrorIdStrings.RunspaceCannotBeFound, clientRunspacePoolId); RemoteSessionStateMachineEventArgs runspaceNotFoundArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.FatalError, reasonOfFailure); RaiseEvent(runspaceNotFoundArg); } break; case RemotingTargetInterface.PowerShell: clientRunspacePoolId = fsmEventArg.RemoteData.RunspacePoolId; runspacePoolDriver = _session.GetRunspacePoolDriver(clientRunspacePoolId); runspacePoolDriver.DataStructureHandler.DispatchMessageToPowerShell(fsmEventArg.RemoteData); break; default: s_trace.WriteLine("Server received data unknown targetInterface: {0}", targetInterface); PSRemotingDataStructureException reasonOfFailure2 = new PSRemotingDataStructureException(RemotingErrorIdStrings.ReceivedUnsupportedRemotingTargetInterfaceType, targetInterface); RemoteSessionStateMachineEventArgs unknownTargetArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.FatalError, reasonOfFailure2); RaiseEvent(unknownTargetArg); break; } } }
/// <summary> /// Closes Session Connection Asynchronously. /// </summary> /// <remarks> /// Caller should register for ConnectionClosed event to get notified /// </remarks> public override void CloseAsync() { RemoteSessionStateMachineEventArgs closeArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close); SessionDataStructureHandler.StateMachine.RaiseEvent(closeArg); }
private void DoNegotiationSending(object sender, RemoteSessionStateMachineEventArgs arg) { using (ClientRemoteSessionDSHandlerStateMachine._trace.TraceMethod()) this.SetState(RemoteSessionState.NegotiationSending, (Exception)null); }
/// <summary> /// Restores connection to a disconnected remote session. Negotiation has already been performed before /// </summary> public override void ReconnectAsync() { RemoteSessionStateMachineEventArgs startReconnectArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.ReconnectStart); SessionDataStructureHandler.StateMachine.RaiseEvent(startReconnectArg); }
private void SetStateHandler(object sender, RemoteSessionStateMachineEventArgs eventArgs) { using (ClientRemoteSessionDSHandlerStateMachine._trace.TraceMethod()) { switch (eventArgs.StateEvent) { case RemoteSessionEvent.NegotiationSendCompleted: this.SetState(RemoteSessionState.NegotiationSent, (Exception)null); break; case RemoteSessionEvent.NegotiationReceived: if (eventArgs.RemoteSessionCapability == null) { throw ClientRemoteSessionDSHandlerStateMachine._trace.NewArgumentException(nameof(eventArgs)); } this.SetState(RemoteSessionState.NegotiationReceived, (Exception)null); break; case RemoteSessionEvent.NegotiationCompleted: this.SetState(RemoteSessionState.Established, (Exception)null); break; case RemoteSessionEvent.CloseCompleted: this.SetState(RemoteSessionState.Closed, eventArgs.Reason); break; case RemoteSessionEvent.CloseFailed: this.SetState(RemoteSessionState.Closed, eventArgs.Reason); break; case RemoteSessionEvent.ConnectFailed: this.SetState(RemoteSessionState.ClosingConnection, eventArgs.Reason); break; case RemoteSessionEvent.KeySent: if (this._state != RemoteSessionState.Established && this._state != RemoteSessionState.EstablishedAndKeyRequested) { break; } this.SetState(RemoteSessionState.EstablishedAndKeySent, eventArgs.Reason); this._keyExchangeTimer = new Timer(); this._keyExchangeTimer.AutoReset = false; this._keyExchangeTimer.Elapsed += new ElapsedEventHandler(this.HandleKeyExchangeTimeout); this._keyExchangeTimer.Interval = 180000.0; break; case RemoteSessionEvent.KeyReceived: if (this._state != RemoteSessionState.EstablishedAndKeySent) { break; } if (this._keyExchangeTimer != null) { this._keyExchangeTimer.Enabled = false; this._keyExchangeTimer.Dispose(); this._keyExchangeTimer = (Timer)null; } this.SetState(RemoteSessionState.EstablishedAndKeyExchanged, eventArgs.Reason); break; case RemoteSessionEvent.KeyRequested: if (this._state != RemoteSessionState.Established) { break; } this.SetState(RemoteSessionState.EstablishedAndKeyRequested, eventArgs.Reason); break; } } }
/// <summary> /// Start the key exchange process /// </summary> internal override void StartKeyExchange() { if (SessionDataStructureHandler.StateMachine.State == RemoteSessionState.Established || SessionDataStructureHandler.StateMachine.State == RemoteSessionState.EstablishedAndKeyRequested) { // Start the key sending process string localPublicKey = null; bool ret = false; RemoteSessionStateMachineEventArgs eventArgs = null; Exception exception = null; try { ret = _cryptoHelper.ExportLocalPublicKey(out localPublicKey); } catch (PSCryptoException cryptoException) { ret = false; exception = cryptoException; } if (!ret) { // we need to complete the key exchange // since the crypto helper will be waiting on it CompleteKeyExchange(); // exporting local public key failed // set state to Closed eventArgs = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.KeySendFailed, exception); SessionDataStructureHandler.StateMachine.RaiseEvent(eventArgs); } // send using data structure handler eventArgs = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.KeySent); SessionDataStructureHandler.StateMachine.RaiseEvent(eventArgs); SessionDataStructureHandler.SendPublicKeyAsync(localPublicKey); } }
/// <summary> /// This method is used by all classes to raise a FSM event. /// The method will queue the event. The event queue will be handled in /// a thread safe manner by a single dedicated thread. /// </summary> /// <param name="fsmEventArg"> /// This parameter contains the event to be raised. /// </param> /// <exception cref="ArgumentNullException"> /// If the parameter is null. /// </exception> internal void RaiseEvent(RemoteSessionStateMachineEventArgs fsmEventArg) { // make sure only one thread is processing events. lock (_syncObject) { s_trace.WriteLine("Event received : {0}", fsmEventArg.StateEvent); _processPendingEventsQueue.Enqueue(fsmEventArg); if (_eventsInProcess) { return; } _eventsInProcess = true; } ProcessEvents(); // currently server state machine doesn't raise events // this will allow server state machine to raise events. //RaiseStateMachineEvents(); }
/// <summary> /// Handles an encrypted session key received from the other side /// </summary> /// <param name="sender">sender of this event</param> /// <param name="eventArgs">arguments that contain the remote /// public key</param> private void HandleEncryptedSessionKeyReceived(object sender, RemoteDataEventArgs<string> eventArgs) { if (SessionDataStructureHandler.StateMachine.State == RemoteSessionState.EstablishedAndKeySent) { string encryptedSessionKey = eventArgs.Data; bool ret = _cryptoHelper.ImportEncryptedSessionKey(encryptedSessionKey); RemoteSessionStateMachineEventArgs args = null; if (!ret) { // importing remote public key failed // set state to closed args = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.KeyReceiveFailed); SessionDataStructureHandler.StateMachine.RaiseEvent(args); } // complete the key exchange process CompleteKeyExchange(); args = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.KeyReceived); SessionDataStructureHandler.StateMachine.RaiseEvent(args); } }
/// <summary> /// This is the handler for Start event of the FSM. This is the beginning of everything /// else. From this moment on, the FSM will proceeds step by step to eventually reach /// Established state or Closed state. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoCreateSession(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.CreateSession, "StateEvent must be CreateSession"); Dbg.Assert(_state == RemoteSessionState.Idle, "DoCreateSession cannot only be called in Idle state"); DoNegotiationPending(sender, fsmEventArg); } }
/// <summary> /// Handles a request for public key from the server /// </summary> /// <param name="sender">send of this event, unused</param> /// <param name="eventArgs">arguments describing this event, unused</param> private void HandlePublicKeyRequestReceived(object sender, RemoteDataEventArgs<string> eventArgs) { if (SessionDataStructureHandler.StateMachine.State == RemoteSessionState.Established) { RemoteSessionStateMachineEventArgs args = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.KeyRequested); SessionDataStructureHandler.StateMachine.RaiseEvent(args); StartKeyExchange(); } }
/// <summary> /// This is the handler for the NegotiationReceived event. /// It sets the new state to be NegotiationReceived. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// If the parameter <paramref name="fsmEventArg"/> is not NegotiationReceived event or it does not hold the /// client negotiation packet. /// </exception> private void DoNegotiationReceived(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.NegotiationReceived, "StateEvent must be NegotiationReceived"); Dbg.Assert(fsmEventArg.RemoteSessionCapability != null, "RemoteSessioncapability must be non-null"); Dbg.Assert(_state == RemoteSessionState.NegotiationPending, "state must be in NegotiationPending state"); if (fsmEventArg.StateEvent != RemoteSessionEvent.NegotiationReceived) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } if (fsmEventArg.RemoteSessionCapability == null) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } SetState(RemoteSessionState.NegotiationReceived, null); } }
/// <summary> /// Examines the negotiation packet received from the server /// </summary> /// <param name="sender"></param> /// <param name="arg"></param> private void HandleNegotiationReceived(object sender, RemoteSessionNegotiationEventArgs arg) { using (s_trace.TraceEventHandlers()) { if (arg == null) { throw PSTraceSource.NewArgumentNullException("arg"); } if (arg.RemoteSessionCapability == null) { throw PSTraceSource.NewArgumentException("arg"); } Context.ServerCapability = arg.RemoteSessionCapability; try { // This will throw if there is an error running the algorithm RunClientNegotiationAlgorithm(Context.ServerCapability); RemoteSessionStateMachineEventArgs negotiationCompletedArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationCompleted); SessionDataStructureHandler.StateMachine.RaiseEvent(negotiationCompletedArg); } catch (PSRemotingDataStructureException dse) { RemoteSessionStateMachineEventArgs negotiationFailedArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationFailed, dse); SessionDataStructureHandler.StateMachine.RaiseEvent(negotiationFailedArg); } } }
/// <summary> /// This is the handler for NegotiationSendCompleted event. /// It sets the new state to be NegotiationSent. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoNegotiationCompleted(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(_state == RemoteSessionState.NegotiationSending, "State must be NegotiationSending"); Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.NegotiationSendCompleted, "StateEvent must be NegotiationSendCompleted"); SetState(RemoteSessionState.NegotiationSent, null); } }
private void HandleServerRemoteSessionClosed( Object sender, RemoteSessionStateMachineEventArgs eventArgs) { Exception reasonForClose = null; if (null != eventArgs) { reasonForClose = eventArgs.Reason; } Close(reasonForClose); }
/// <summary> /// This is the handler for MessageReceived event. It dispatches the data to various components /// that uses the data. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// If the parameter <paramref name="fsmEventArg"/> does not contain remote data. /// </exception> internal void DoMessageReceived(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } if (fsmEventArg.RemoteData == null) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } Dbg.Assert(_state == RemoteSessionState.Established || _state == RemoteSessionState.EstablishedAndKeyExchanged || _state == RemoteSessionState.EstablishedAndKeyReceived || _state == RemoteSessionState.EstablishedAndKeySent, //server session will never be in this state.. TODO- remove this "State must be Established or EstablishedAndKeySent or EstablishedAndKeyReceived or EstablishedAndKeyExchanged"); RemotingTargetInterface targetInterface = fsmEventArg.RemoteData.TargetInterface; RemotingDataType dataType = fsmEventArg.RemoteData.DataType; Guid clientRunspacePoolId; ServerRunspacePoolDriver runspacePoolDriver; //string errorMessage = null; RemoteDataEventArgs remoteDataForSessionArg = null; switch (targetInterface) { case RemotingTargetInterface.Session: { switch (dataType) { // GETBACK case RemotingDataType.CreateRunspacePool: remoteDataForSessionArg = new RemoteDataEventArgs(fsmEventArg.RemoteData); _session.SessionDataStructureHandler.RaiseDataReceivedEvent(remoteDataForSessionArg); break; default: Dbg.Assert(false, "Should never reach here"); break; } } break; case RemotingTargetInterface.RunspacePool: // GETBACK clientRunspacePoolId = fsmEventArg.RemoteData.RunspacePoolId; runspacePoolDriver = _session.GetRunspacePoolDriver(clientRunspacePoolId); if (runspacePoolDriver != null) { runspacePoolDriver.DataStructureHandler.ProcessReceivedData(fsmEventArg.RemoteData); } else { s_trace.WriteLine(@"Server received data for Runspace (id: {0}), but the Runspace cannot be found", clientRunspacePoolId); PSRemotingDataStructureException reasonOfFailure = new PSRemotingDataStructureException(RemotingErrorIdStrings.RunspaceCannotBeFound, clientRunspacePoolId); RemoteSessionStateMachineEventArgs runspaceNotFoundArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.FatalError, reasonOfFailure); RaiseEvent(runspaceNotFoundArg); } break; case RemotingTargetInterface.PowerShell: clientRunspacePoolId = fsmEventArg.RemoteData.RunspacePoolId; runspacePoolDriver = _session.GetRunspacePoolDriver(clientRunspacePoolId); runspacePoolDriver.DataStructureHandler.DispatchMessageToPowerShell(fsmEventArg.RemoteData); break; default: s_trace.WriteLine("Server received data unknown targetInterface: {0}", targetInterface); PSRemotingDataStructureException reasonOfFailure2 = new PSRemotingDataStructureException(RemotingErrorIdStrings.ReceivedUnsupportedRemotingTargetInterfaceType, targetInterface); RemoteSessionStateMachineEventArgs unknownTargetArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.FatalError, reasonOfFailure2); RaiseEvent(unknownTargetArg); break; } } }
private void HandleReconnectComplete(object sender, EventArgs args) { RemoteSessionStateMachineEventArgs arg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.ReconnectCompleted); this.StateMachine.RaiseEvent(arg, false); }
/// <summary> /// This is the handler for FatalError event. It directly calls the DoClose, which /// is the Close event handler. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> does not contains FatalError event. /// </exception> private void DoFatalError(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.FatalError, "StateEvent must be FatalError"); if (fsmEventArg.StateEvent != RemoteSessionEvent.FatalError) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } DoClose(this, fsmEventArg); } }
internal void HandleTransportError(object sender, TransportErrorOccuredEventArgs e) { PSRemotingTransportRedirectException exception = e.Exception as PSRemotingTransportRedirectException; if ((exception != null) && (this.maxUriRedirectionCount > 0)) { Exception exception2 = null; try { this.maxUriRedirectionCount--; this.PerformURIRedirection(exception.RedirectLocation); return; } catch (ArgumentNullException exception3) { exception2 = exception3; } catch (UriFormatException exception4) { exception2 = exception4; } if (exception2 != null) { PSRemotingTransportException exception5 = new PSRemotingTransportException(PSRemotingErrorId.RedirectedURINotWellFormatted, RemotingErrorIdStrings.RedirectedURINotWellFormatted, new object[] { this._session.Context.RemoteAddress.OriginalString, exception.RedirectLocation }) { TransportMessage = e.Exception.TransportMessage }; e.Exception = exception5; } } RemoteSessionEvent connectFailed = RemoteSessionEvent.ConnectFailed; switch (e.ReportingTransportMethod) { case TransportMethodEnum.CreateShellEx: connectFailed = RemoteSessionEvent.ConnectFailed; break; case TransportMethodEnum.SendShellInputEx: case TransportMethodEnum.CommandInputEx: connectFailed = RemoteSessionEvent.SendFailed; break; case TransportMethodEnum.ReceiveShellOutputEx: case TransportMethodEnum.ReceiveCommandOutputEx: connectFailed = RemoteSessionEvent.ReceiveFailed; break; case TransportMethodEnum.CloseShellOperationEx: connectFailed = RemoteSessionEvent.CloseFailed; break; case TransportMethodEnum.DisconnectShellEx: connectFailed = RemoteSessionEvent.DisconnectFailed; break; case TransportMethodEnum.ReconnectShellEx: connectFailed = RemoteSessionEvent.ReconnectFailed; break; } RemoteSessionStateMachineEventArgs arg = new RemoteSessionStateMachineEventArgs(connectFailed, e.Exception); this._stateMachine.RaiseEvent(arg, false); }
/// <summary> /// This is the handler for Close event. It closes the connection. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoClose(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } RemoteSessionState oldState = _state; switch (oldState) { case RemoteSessionState.ClosingConnection: case RemoteSessionState.Closed: // do nothing break; case RemoteSessionState.Connecting: case RemoteSessionState.Connected: case RemoteSessionState.Established: case RemoteSessionState.EstablishedAndKeySent: //server session will never be in this state.. TODO- remove this case RemoteSessionState.EstablishedAndKeyReceived: case RemoteSessionState.EstablishedAndKeyExchanged: case RemoteSessionState.NegotiationReceived: case RemoteSessionState.NegotiationSent: case RemoteSessionState.NegotiationSending: SetState(RemoteSessionState.ClosingConnection, fsmEventArg.Reason); _session.SessionDataStructureHandler.CloseConnectionAsync(fsmEventArg.Reason); break; case RemoteSessionState.Idle: case RemoteSessionState.UndefinedState: default: Exception forcedCloseException = new PSRemotingTransportException(fsmEventArg.Reason, RemotingErrorIdStrings.ForceClosed); SetState(RemoteSessionState.Closed, forcedCloseException); break; } CleanAll(); } }
internal void DoMessageReceived(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (_trace.TraceEventHandlers()) { Guid runspacePoolId; if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } if (fsmEventArg.RemoteData == null) { throw PSTraceSource.NewArgumentException("fsmEventArg"); } RemotingTargetInterface targetInterface = fsmEventArg.RemoteData.TargetInterface; RemotingDataType dataType = fsmEventArg.RemoteData.DataType; RemoteDataEventArgs arg = null; switch (targetInterface) { case RemotingTargetInterface.Session: switch (dataType) { case RemotingDataType.CreateRunspacePool: { arg = new RemoteDataEventArgs(fsmEventArg.RemoteData); this._session.SessionDataStructureHandler.RaiseDataReceivedEvent(arg); } break; } return; case RemotingTargetInterface.RunspacePool: { runspacePoolId = fsmEventArg.RemoteData.RunspacePoolId; ServerRunspacePoolDriver runspacePoolDriver = this._session.GetRunspacePoolDriver(runspacePoolId); if (runspacePoolDriver == null) { break; } runspacePoolDriver.DataStructureHandler.ProcessReceivedData(fsmEventArg.RemoteData); return; } case RemotingTargetInterface.PowerShell: runspacePoolId = fsmEventArg.RemoteData.RunspacePoolId; this._session.GetRunspacePoolDriver(runspacePoolId).DataStructureHandler.DispatchMessageToPowerShell(fsmEventArg.RemoteData); return; default: goto Label_0151; } _trace.WriteLine("Server received data for Runspace (id: {0}), \r\n but the Runspace cannot be found", new object[] { runspacePoolId }); PSRemotingDataStructureException reason = new PSRemotingDataStructureException(RemotingErrorIdStrings.RunspaceCannotBeFound, new object[] { runspacePoolId }); RemoteSessionStateMachineEventArgs args2 = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.FatalError, reason); this.RaiseEvent(args2); return; Label_0151 :; _trace.WriteLine("Server received data unknown targetInterface: {0}", new object[] { targetInterface }); PSRemotingDataStructureException exception2 = new PSRemotingDataStructureException(RemotingErrorIdStrings.ReceivedUnsupportedRemotingTargetInterfaceType, new object[] { targetInterface }); RemoteSessionStateMachineEventArgs args3 = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.FatalError, exception2); this.RaiseEvent(args3); } }
/// <summary> /// This is the handler for CloseCompleted event. It sets the new state to be Closed. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoCloseCompleted(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.CloseCompleted, "StateEvent must be CloseCompleted"); SetState(RemoteSessionState.Closed, fsmEventArg.Reason); // Close the session only after changing the state..this way // state machine will not process anything. _session.Close(fsmEventArg); CleanAll(); } }
/// <summary> /// This method is used by the input queue dispatching mechanism. /// It examines the data and takes appropriate actions. /// </summary> /// <param name="dataArg"> /// The received client data. /// </param> /// <exception cref="ArgumentNullException"> /// If the parameter is null. /// </exception> internal override void RaiseDataReceivedEvent(RemoteDataEventArgs dataArg) { if (dataArg == null) { throw PSTraceSource.NewArgumentNullException("dataArg"); } RemoteDataObject <PSObject> rcvdData = dataArg.ReceivedData; RemotingTargetInterface targetInterface = rcvdData.TargetInterface; RemotingDataType dataType = rcvdData.DataType; Dbg.Assert(targetInterface == RemotingTargetInterface.Session, "targetInterface must be Session"); switch (dataType) { case RemotingDataType.CreateRunspacePool: { // At this point, the negotiation is complete, so // need to import the clients public key CreateRunspacePoolReceived.SafeInvoke(this, dataArg); } break; case RemotingDataType.CloseSession: PSRemotingDataStructureException reasonOfClose = new PSRemotingDataStructureException(RemotingErrorIdStrings.ClientRequestedToCloseSession); RemoteSessionStateMachineEventArgs closeSessionArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close, reasonOfClose); _stateMachine.RaiseEvent(closeSessionArg); break; case RemotingDataType.SessionCapability: RemoteSessionCapability capability = null; try { capability = RemotingDecoder.GetSessionCapability(rcvdData.Data); } catch (PSRemotingDataStructureException dse) { // this will happen if expected properties are not // received for session capability throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerNotFoundCapabilityProperties, dse.Message, PSVersionInfo.GitCommitId, RemotingConstants.ProtocolVersion); } RemoteSessionStateMachineEventArgs capabilityArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationReceived); capabilityArg.RemoteSessionCapability = capability; _stateMachine.RaiseEvent(capabilityArg); if (NegotiationReceived != null) { RemoteSessionNegotiationEventArgs negotiationArg = new RemoteSessionNegotiationEventArgs(capability); negotiationArg.RemoteData = rcvdData; NegotiationReceived.SafeInvoke(this, negotiationArg); } break; case RemotingDataType.PublicKey: { string remotePublicKey = RemotingDecoder.GetPublicKey(rcvdData.Data); PublicKeyReceived.SafeInvoke(this, new RemoteDataEventArgs <string>(remotePublicKey)); } break; default: throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ReceivedUnsupportedAction, dataType); } }
/// <summary> /// This is the handler for ReceivedFailed event. /// This is an indication that the wire layer IO is no longer connected. So it raises /// a Close event to trigger a connection shutdown. /// </summary> /// <param name="sender"></param> /// <param name="fsmEventArg"> /// This parameter contains the FSM event. /// </param> /// /// <exception cref="ArgumentNullException"> /// If the parameter <paramref name="fsmEventArg"/> is null. /// </exception> private void DoReceiveFailed(object sender, RemoteSessionStateMachineEventArgs fsmEventArg) { using (s_trace.TraceEventHandlers()) { if (fsmEventArg == null) { throw PSTraceSource.NewArgumentNullException("fsmEventArg"); } Dbg.Assert(fsmEventArg.StateEvent == RemoteSessionEvent.ReceiveFailed, "StateEvent must be ReceivedFailed"); RemoteSessionStateMachineEventArgs closeArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close); RaiseEventPrivate(closeArg); } }
/// <summary> /// Dispatches data when it arrives from the input queue. /// </summary> /// <param name="sender"></param> /// <param name="dataArg"> /// arg which contains the data received from input queue /// </param> internal void DispatchInputQueueData(object sender, RemoteDataEventArgs dataArg) { if (dataArg is null) { throw PSTraceSource.NewArgumentNullException(nameof(dataArg)); } RemoteDataObject <PSObject> rcvdData = dataArg.ReceivedData; if (rcvdData is null) { throw PSTraceSource.NewArgumentException(nameof(dataArg)); } RemotingDestination destination = rcvdData.Destination; if ((destination & RemotingDestination.Client) != RemotingDestination.Client) { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.RemotingDestinationNotForMe, RemotingDestination.Client, destination); } RemotingTargetInterface targetInterface = rcvdData.TargetInterface; switch (targetInterface) { case RemotingTargetInterface.Session: { // Messages for session can cause statemachine state to change. // These messages are first processed by Sessiondata structure handler and depending // on the type of message, appropriate event is raised in state machine ProcessSessionMessages(dataArg); break; } case RemotingTargetInterface.RunspacePool: case RemotingTargetInterface.PowerShell: // Non Session messages do not change the state of the statemachine. // However instead of forwarding them to Runspace/pipeline here, an // event is raised in state machine which verified that state is // suitable for accepting these messages. if state is suitable statemachine // will call DoMessageForwading which will forward the messages appropriately RemoteSessionStateMachineEventArgs msgRcvArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.MessageReceived, null); if (StateMachine.CanByPassRaiseEvent(msgRcvArg)) { ProcessNonSessionMessages(dataArg.ReceivedData); } else { StateMachine.RaiseEvent(msgRcvArg); } break; default: { Dbg.Assert(false, "we should not be encountering this"); } break; } }
/// <summary> /// Closes Session Connection Asynchronously. /// </summary> /// <remarks> /// Caller should register for ConnectionClosed event to get notified /// </remarks> public override void CloseAsync() { RemoteSessionStateMachineEventArgs closeArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close); SessionDataStructureHandler.StateMachine.RaiseEvent(closeArg); }
/// <summary> /// Handler which handles transport errors. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> internal void HandleTransportError(object sender, TransportErrorOccuredEventArgs e) { Dbg.Assert(e != null, "HandleTransportError expects non-null eventargs"); // handle uri redirections PSRemotingTransportRedirectException redirectException = e.Exception as PSRemotingTransportRedirectException; if ((redirectException != null) && (_maxUriRedirectionCount > 0)) { Exception exception = null; try { // honor max redirection count given by the user. _maxUriRedirectionCount--; PerformURIRedirection(redirectException.RedirectLocation); return; } catch (ArgumentNullException argumentException) { exception = argumentException; } catch (UriFormatException uriFormatException) { exception = uriFormatException; } // if we are here, there must be an exception constructing a uri if (exception != null) { PSRemotingTransportException newException = new PSRemotingTransportException(PSRemotingErrorId.RedirectedURINotWellFormatted, RemotingErrorIdStrings.RedirectedURINotWellFormatted, _session.Context.RemoteAddress.OriginalString, redirectException.RedirectLocation); newException.TransportMessage = e.Exception.TransportMessage; e.Exception = newException; } } RemoteSessionEvent sessionEvent = RemoteSessionEvent.ConnectFailed; switch (e.ReportingTransportMethod) { case TransportMethodEnum.CreateShellEx: sessionEvent = RemoteSessionEvent.ConnectFailed; break; case TransportMethodEnum.SendShellInputEx: case TransportMethodEnum.CommandInputEx: sessionEvent = RemoteSessionEvent.SendFailed; break; case TransportMethodEnum.ReceiveShellOutputEx: case TransportMethodEnum.ReceiveCommandOutputEx: sessionEvent = RemoteSessionEvent.ReceiveFailed; break; case TransportMethodEnum.CloseShellOperationEx: sessionEvent = RemoteSessionEvent.CloseFailed; break; case TransportMethodEnum.DisconnectShellEx: sessionEvent = RemoteSessionEvent.DisconnectFailed; break; case TransportMethodEnum.ReconnectShellEx: sessionEvent = RemoteSessionEvent.ReconnectFailed; break; } RemoteSessionStateMachineEventArgs errorArgs = new RemoteSessionStateMachineEventArgs(sessionEvent, e.Exception); _stateMachine.RaiseEvent(errorArgs); }
/// <summary> /// Handler to be used in cases, where setting the state is the /// only task being performed. This method also asserts /// if the specified event is valid for the current state of /// the state machine. /// </summary> /// <param name="sender">Sender of this event.</param> /// <param name="eventArgs">Event args.</param> private void SetStateHandler(object sender, RemoteSessionStateMachineEventArgs eventArgs) { switch (eventArgs.StateEvent) { case RemoteSessionEvent.NegotiationCompleted: { Dbg.Assert(_state == RemoteSessionState.NegotiationReceived, "State can be set to Established only when current state is NegotiationReceived"); SetState(RemoteSessionState.Established, null); } break; case RemoteSessionEvent.NegotiationReceived: { Dbg.Assert(eventArgs.RemoteSessionCapability != null, "State can be set to NegotiationReceived only when RemoteSessionCapability is not null"); if (eventArgs.RemoteSessionCapability == null) { throw PSTraceSource.NewArgumentException(nameof(eventArgs)); } SetState(RemoteSessionState.NegotiationReceived, null); } break; case RemoteSessionEvent.NegotiationSendCompleted: { Dbg.Assert((_state == RemoteSessionState.NegotiationSending) || (_state == RemoteSessionState.NegotiationSendingOnConnect), "Negotiating send can be completed only when current state is NegotiationSending"); SetState(RemoteSessionState.NegotiationSent, null); } break; case RemoteSessionEvent.ConnectFailed: { Dbg.Assert(_state == RemoteSessionState.Connecting, "A ConnectFailed event can be raised only when the current state is Connecting"); SetState(RemoteSessionState.ClosingConnection, eventArgs.Reason); } break; case RemoteSessionEvent.CloseFailed: { SetState(RemoteSessionState.Closed, eventArgs.Reason); } break; case RemoteSessionEvent.CloseCompleted: { SetState(RemoteSessionState.Closed, eventArgs.Reason); } break; case RemoteSessionEvent.KeyRequested: { Dbg.Assert(_state == RemoteSessionState.Established, "Server can request a key only after the client reaches the Established state"); if (_state == RemoteSessionState.Established) { SetState(RemoteSessionState.EstablishedAndKeyRequested, eventArgs.Reason); } } break; case RemoteSessionEvent.KeyReceived: { Dbg.Assert(_state == RemoteSessionState.EstablishedAndKeySent, "Key Receiving can only be raised after reaching the Established state"); if (_state == RemoteSessionState.EstablishedAndKeySent) { Timer tmp = Interlocked.Exchange(ref _keyExchangeTimer, null); if (tmp != null) { tmp.Dispose(); } _keyExchanged = true; SetState(RemoteSessionState.Established, eventArgs.Reason); if (_pendingDisconnect) { // session key exchange is complete, if there is a disconnect pending, process it now _pendingDisconnect = false; DoDisconnect(sender, eventArgs); } } } break; case RemoteSessionEvent.KeySent: { Dbg.Assert(_state >= RemoteSessionState.Established, "Client can send a public key only after reaching the Established state"); Dbg.Assert(!_keyExchanged, "Client should do key exchange only once"); if (_state == RemoteSessionState.Established || _state == RemoteSessionState.EstablishedAndKeyRequested) { SetState(RemoteSessionState.EstablishedAndKeySent, eventArgs.Reason); // start the timer and wait _keyExchangeTimer = new Timer(HandleKeyExchangeTimeout, null, BaseTransportManager.ClientDefaultOperationTimeoutMs, Timeout.Infinite); } } break; case RemoteSessionEvent.DisconnectCompleted: { Dbg.Assert(_state == RemoteSessionState.Disconnecting || _state == RemoteSessionState.RCDisconnecting, "DisconnectCompleted event received while state machine is in wrong state"); if (_state == RemoteSessionState.Disconnecting || _state == RemoteSessionState.RCDisconnecting) { SetState(RemoteSessionState.Disconnected, eventArgs.Reason); } } break; case RemoteSessionEvent.DisconnectFailed: { Dbg.Assert(_state == RemoteSessionState.Disconnecting, "DisconnectCompleted event received while state machine is in wrong state"); if (_state == RemoteSessionState.Disconnecting) { SetState(RemoteSessionState.Disconnected, eventArgs.Reason); // set state to disconnected even TODO. Put some ETW event describing the disconnect process failure } } break; case RemoteSessionEvent.ReconnectCompleted: { Dbg.Assert(_state == RemoteSessionState.Reconnecting, "ReconnectCompleted event received while state machine is in wrong state"); if (_state == RemoteSessionState.Reconnecting) { SetState(RemoteSessionState.Established, eventArgs.Reason); } } break; } }
// TODO: If this is not used remove this // internal override event EventHandler<RemoteDataEventArgs> DataReceived; /// <summary> /// This processes the object received from transport which are /// targeted for session /// </summary> /// <param name="arg"> /// argument contains the data object /// </param> private void ProcessSessionMessages(RemoteDataEventArgs arg) { if (arg == null || arg.ReceivedData == null) { throw PSTraceSource.NewArgumentNullException("arg"); } RemoteDataObject <PSObject> rcvdData = arg.ReceivedData; RemotingTargetInterface targetInterface = rcvdData.TargetInterface; Dbg.Assert(targetInterface == RemotingTargetInterface.Session, "targetInterface must be Session"); RemotingDataType dataType = rcvdData.DataType; switch (dataType) { case RemotingDataType.CloseSession: PSRemotingDataStructureException reasonOfClose = new PSRemotingDataStructureException(RemotingErrorIdStrings.ServerRequestedToCloseSession); RemoteSessionStateMachineEventArgs closeSessionArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.Close, reasonOfClose); _stateMachine.RaiseEvent(closeSessionArg); break; case RemotingDataType.SessionCapability: RemoteSessionCapability capability = null; try { capability = RemotingDecoder.GetSessionCapability(rcvdData.Data); } catch (PSRemotingDataStructureException dse) { // this will happen if expected properties are not // received for session capability throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ClientNotFoundCapabilityProperties, dse.Message, PSVersionInfo.GitCommitId, RemotingConstants.ProtocolVersion); } RemoteSessionStateMachineEventArgs capabilityArg = new RemoteSessionStateMachineEventArgs(RemoteSessionEvent.NegotiationReceived); capabilityArg.RemoteSessionCapability = capability; _stateMachine.RaiseEvent(capabilityArg); RemoteSessionNegotiationEventArgs negotiationArg = new RemoteSessionNegotiationEventArgs(capability); NegotiationReceived.SafeInvoke(this, negotiationArg); break; case RemotingDataType.EncryptedSessionKey: { String encryptedSessionKey = RemotingDecoder.GetEncryptedSessionKey(rcvdData.Data); EncryptedSessionKeyReceived.SafeInvoke(this, new RemoteDataEventArgs <string>(encryptedSessionKey)); } break; case RemotingDataType.PublicKeyRequest: { PublicKeyRequestReceived.SafeInvoke(this, new RemoteDataEventArgs <string>(String.Empty)); } break; default: { throw new PSRemotingDataStructureException(RemotingErrorIdStrings.ReceivedUnsupportedAction, dataType); } } }
private void DoReconnect(object sender, RemoteSessionStateMachineEventArgs arg) { SetState(RemoteSessionState.Reconnecting, null); }
internal bool CanByPassRaiseEvent(RemoteSessionStateMachineEventArgs arg) => arg.StateEvent == RemoteSessionEvent.MessageReceived && (this._state == RemoteSessionState.Established || this._state == RemoteSessionState.EstablishedAndKeyReceived || (this._state == RemoteSessionState.EstablishedAndKeySent || this._state == RemoteSessionState.EstablishedAndKeyExchanged));
/// <summary> /// This method contains all the logic for handling the state machine /// for key exchange. All the different scenarios are covered in this /// </summary> /// <param name="sender">sender of this event, unused</param> /// <param name="eventArgs">event args</param> private void DoKeyExchange(object sender, RemoteSessionStateMachineEventArgs eventArgs) { //There are corner cases with disconnect that can result in client receiving outdated key exchange packets //***TODO*** Deal with this on the client side. Key exchange packets should have additional information //that identify the context of negotiation. Just like callId in SetMax and SetMinRunspaces messages Dbg.Assert(_state >= RemoteSessionState.Established, "Key Receiving can only be raised after reaching the Established state"); switch (eventArgs.StateEvent) { case RemoteSessionEvent.KeyReceived: { //does the server ever start key exchange process??? This may not be required if (_state == RemoteSessionState.EstablishedAndKeyRequested) { // reset the timer Timer tmp = Interlocked.Exchange(ref _keyExchangeTimer, null); if (tmp != null) { tmp.Dispose(); } } // the key import would have been done // set state accordingly SetState(RemoteSessionState.EstablishedAndKeyReceived, eventArgs.Reason); // you need to send an encrypted session key to the client _session.SendEncryptedSessionKey(); } break; case RemoteSessionEvent.KeySent: { if (_state == RemoteSessionState.EstablishedAndKeyReceived) { // key exchange is now complete SetState(RemoteSessionState.EstablishedAndKeyExchanged, eventArgs.Reason); } } break; case RemoteSessionEvent.KeyRequested: { if ((_state == RemoteSessionState.Established) || (_state == RemoteSessionState.EstablishedAndKeyExchanged)) { // the key has been sent set state accordingly SetState(RemoteSessionState.EstablishedAndKeyRequested, eventArgs.Reason); // start the timer _keyExchangeTimer = new Timer(HandleKeyExchangeTimeout, null, BaseTransportManager.ServerDefaultKeepAliveTimeoutMs, Timeout.Infinite); } } break; case RemoteSessionEvent.KeyReceiveFailed: { if ((_state == RemoteSessionState.Established) || (_state == RemoteSessionState.EstablishedAndKeyExchanged)) { return; } DoClose(this, eventArgs); } break; case RemoteSessionEvent.KeySendFailed: { DoClose(this, eventArgs); } break; } }
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(); }