@@ -20,28 +20,29 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
2020 public class NamedPipeServerListener : ServerListenerBase < NamedPipeServerChannel >
2121 {
2222 // This int will be casted to a PipeOptions enum that only exists in .NET Core 2.1 and up which is why it's not available to us in .NET Standard.
23- private const int CurrentUserOnly = 536870912 ;
23+ private const int CurrentUserOnly = 0x20000000 ;
2424
2525 // In .NET Framework, NamedPipeServerStream has a constructor that takes in a PipeSecurity object. We will use reflection to call the constructor,
2626 // since .NET Framework doesn't have the `CurrentUserOnly` PipeOption.
2727 // doc: https://docs.microsoft.com/en-us/dotnet/api/system.io.pipes.namedpipeserverstream.-ctor?view=netframework-4.7.2#System_IO_Pipes_NamedPipeServerStream__ctor_System_String_System_IO_Pipes_PipeDirection_System_Int32_System_IO_Pipes_PipeTransmissionMode_System_IO_Pipes_PipeOptions_System_Int32_System_Int32_System_IO_Pipes_PipeSecurity_
28- private static ConstructorInfo _netFrameworkPipeServerConstructor =
28+ private static readonly ConstructorInfo s_netFrameworkPipeServerConstructor =
2929 typeof ( NamedPipeServerStream ) . GetConstructor ( new [ ] { typeof ( string ) , typeof ( PipeDirection ) , typeof ( int ) , typeof ( PipeTransmissionMode ) , typeof ( PipeOptions ) , typeof ( int ) , typeof ( int ) , typeof ( PipeSecurity ) } ) ;
3030
31- private ILogger logger ;
32- private string inOutPipeName ;
33- private readonly string outPipeName ;
34- private NamedPipeServerStream inOutPipeServer ;
35- private NamedPipeServerStream outPipeServer ;
31+ private readonly ILogger _logger ;
32+ private readonly string _inOutPipeName ;
33+ private readonly string _outPipeName ;
34+
35+ private NamedPipeServerStream _inOutPipeServer ;
36+ private NamedPipeServerStream _outPipeServer ;
3637
3738 public NamedPipeServerListener (
3839 MessageProtocolType messageProtocolType ,
3940 string inOutPipeName ,
4041 ILogger logger )
4142 : base ( messageProtocolType )
4243 {
43- this . logger = logger ;
44- this . inOutPipeName = inOutPipeName ;
44+ _logger = logger ;
45+ _inOutPipeName = inOutPipeName ;
4546 }
4647
4748 public NamedPipeServerListener (
@@ -51,88 +52,21 @@ public NamedPipeServerListener(
5152 ILogger logger )
5253 : base ( messageProtocolType )
5354 {
54- this . logger = logger ;
55- this . inOutPipeName = inPipeName ;
56- this . outPipeName = outPipeName ;
55+ _logger = logger ;
56+ _inOutPipeName = inPipeName ;
57+ _outPipeName = outPipeName ;
5758 }
5859
5960 public override void Start ( )
6061 {
6162 try
6263 {
63- // If we're running in Windows PowerShell, we use the constructor via Reflection
64- if ( RuntimeInformation . FrameworkDescription . StartsWith ( ".NET Framework" ) )
65- {
66- PipeSecurity pipeSecurity = new PipeSecurity ( ) ;
67-
68- WindowsIdentity identity = WindowsIdentity . GetCurrent ( ) ;
69- WindowsPrincipal principal = new WindowsPrincipal ( identity ) ;
70-
71- if ( principal . IsInRole ( WindowsBuiltInRole . Administrator ) )
72- {
73- // Allow the Administrators group full access to the pipe.
74- pipeSecurity . AddAccessRule ( new PipeAccessRule (
75- new SecurityIdentifier ( WellKnownSidType . BuiltinAdministratorsSid , null ) . Translate ( typeof ( NTAccount ) ) ,
76- PipeAccessRights . FullControl , AccessControlType . Allow ) ) ;
77- }
78- else
79- {
80- // Allow the current user read/write access to the pipe.
81- pipeSecurity . AddAccessRule ( new PipeAccessRule (
82- WindowsIdentity . GetCurrent ( ) . User ,
83- PipeAccessRights . ReadWrite , AccessControlType . Allow ) ) ;
84- }
85-
86- _netFrameworkPipeServerConstructor . Invoke ( new object [ ]
87- {
88- inOutPipeName ,
89- PipeDirection . InOut ,
90- 1 , // maxNumberOfServerInstances
91- PipeTransmissionMode . Byte ,
92- PipeOptions . Asynchronous ,
93- 1024 , // inBufferSize
94- 1024 , // outBufferSize
95- pipeSecurity
96- } ) ;
97-
98- if ( this . outPipeName != null )
99- {
100- _netFrameworkPipeServerConstructor . Invoke ( new object [ ]
101- {
102- outPipeName ,
103- PipeDirection . InOut ,
104- 1 , // maxNumberOfServerInstances
105- PipeTransmissionMode . Byte ,
106- PipeOptions . Asynchronous ,
107- 1024 , // inBufferSize
108- 1024 , // outBufferSize
109- pipeSecurity
110- } ) ;
111- }
112- }
113- else
114- {
115- this . inOutPipeServer = new NamedPipeServerStream (
116- pipeName : inOutPipeName ,
117- direction : PipeDirection . InOut ,
118- maxNumberOfServerInstances : 1 ,
119- transmissionMode : PipeTransmissionMode . Byte ,
120- options : PipeOptions . Asynchronous | ( PipeOptions ) CurrentUserOnly ) ;
121- if ( this . outPipeName != null )
122- {
123- this . outPipeServer = new NamedPipeServerStream (
124- pipeName : outPipeName ,
125- direction : PipeDirection . Out ,
126- maxNumberOfServerInstances : 1 ,
127- transmissionMode : PipeTransmissionMode . Byte ,
128- options : ( PipeOptions ) CurrentUserOnly ) ;
129- }
130- }
64+ _inOutPipeServer = ConnectNamedPipe ( _inOutPipeName , _outPipeName , out _outPipeServer ) ;
13165 ListenForConnection ( ) ;
13266 }
13367 catch ( IOException e )
13468 {
135- this . logger . Write (
69+ _logger . Write (
13670 LogLevel . Verbose ,
13771 "Named pipe server failed to start due to exception:\r \n \r \n " + e . Message ) ;
13872
@@ -142,22 +76,98 @@ public override void Start()
14276
14377 public override void Stop ( )
14478 {
145- if ( this . inOutPipeServer != null )
79+ if ( _inOutPipeServer != null )
14680 {
147- this . logger . Write ( LogLevel . Verbose , "Named pipe server shutting down..." ) ;
81+ _logger . Write ( LogLevel . Verbose , "Named pipe server shutting down..." ) ;
14882
149- this . inOutPipeServer . Dispose ( ) ;
83+ _inOutPipeServer . Dispose ( ) ;
15084
151- this . logger . Write ( LogLevel . Verbose , "Named pipe server has been disposed." ) ;
85+ _logger . Write ( LogLevel . Verbose , "Named pipe server has been disposed." ) ;
15286 }
153- if ( this . outPipeServer != null )
87+
88+ if ( _outPipeServer != null )
89+ {
90+ _logger . Write ( LogLevel . Verbose , $ "Named out pipe server { _outPipeServer } shutting down...") ;
91+
92+ _outPipeServer . Dispose ( ) ;
93+
94+ _logger . Write ( LogLevel . Verbose , $ "Named out pipe server { _outPipeServer } has been disposed.") ;
95+ }
96+ }
97+
98+ private static NamedPipeServerStream ConnectNamedPipe (
99+ string inOutPipeName ,
100+ string outPipeName ,
101+ out NamedPipeServerStream outPipe )
102+ {
103+ // .NET Core implementation is simplest so try that first
104+ if ( Utils . IsNetCore )
154105 {
155- this . logger . Write ( LogLevel . Verbose , $ "Named out pipe server { outPipeServer } shutting down...") ;
106+ outPipe = outPipeName == null
107+ ? null
108+ : new NamedPipeServerStream (
109+ pipeName : outPipeName ,
110+ direction : PipeDirection . Out ,
111+ maxNumberOfServerInstances : 1 ,
112+ transmissionMode : PipeTransmissionMode . Byte ,
113+ options : ( PipeOptions ) CurrentUserOnly ) ;
114+
115+ return new NamedPipeServerStream (
116+ pipeName : inOutPipeName ,
117+ direction : PipeDirection . InOut ,
118+ maxNumberOfServerInstances : 1 ,
119+ transmissionMode : PipeTransmissionMode . Byte ,
120+ options : PipeOptions . Asynchronous | ( PipeOptions ) CurrentUserOnly ) ;
121+ }
122+
123+ // Now deal with Windows PowerShell
124+ // We need to use reflection to get a nice constructor
156125
157- this . outPipeServer . Dispose ( ) ;
126+ PipeSecurity pipeSecurity = new PipeSecurity ( ) ;
158127
159- this . logger . Write ( LogLevel . Verbose , $ "Named out pipe server { outPipeServer } has been disposed.") ;
128+ WindowsIdentity identity = WindowsIdentity . GetCurrent ( ) ;
129+ WindowsPrincipal principal = new WindowsPrincipal ( identity ) ;
130+
131+ if ( principal . IsInRole ( WindowsBuiltInRole . Administrator ) )
132+ {
133+ // Allow the Administrators group full access to the pipe.
134+ pipeSecurity . AddAccessRule ( new PipeAccessRule (
135+ new SecurityIdentifier ( WellKnownSidType . BuiltinAdministratorsSid , null ) . Translate ( typeof ( NTAccount ) ) ,
136+ PipeAccessRights . FullControl , AccessControlType . Allow ) ) ;
137+ }
138+ else
139+ {
140+ // Allow the current user read/write access to the pipe.
141+ pipeSecurity . AddAccessRule ( new PipeAccessRule (
142+ WindowsIdentity . GetCurrent ( ) . User ,
143+ PipeAccessRights . ReadWrite , AccessControlType . Allow ) ) ;
160144 }
145+
146+ outPipe = outPipeName == null
147+ ? null
148+ : ( NamedPipeServerStream ) s_netFrameworkPipeServerConstructor . Invoke (
149+ new object [ ] {
150+ outPipeName ,
151+ PipeDirection . InOut ,
152+ 1 , // maxNumberOfServerInstances
153+ PipeTransmissionMode . Byte ,
154+ PipeOptions . Asynchronous ,
155+ 1024 , // inBufferSize
156+ 1024 , // outBufferSize
157+ pipeSecurity
158+ } ) ;
159+
160+ return ( NamedPipeServerStream ) s_netFrameworkPipeServerConstructor . Invoke (
161+ new object [ ] {
162+ inOutPipeName ,
163+ PipeDirection . InOut ,
164+ 1 , // maxNumberOfServerInstances
165+ PipeTransmissionMode . Byte ,
166+ PipeOptions . Asynchronous ,
167+ 1024 , // inBufferSize
168+ 1024 , // outBufferSize
169+ pipeSecurity
170+ } ) ;
161171 }
162172
163173 private void ListenForConnection ( )
@@ -166,18 +176,18 @@ private void ListenForConnection()
166176 {
167177 try
168178 {
169- var connectionTasks = new List < Task > { WaitForConnectionAsync ( this . inOutPipeServer ) } ;
170- if ( this . outPipeServer != null )
179+ var connectionTasks = new List < Task > { WaitForConnectionAsync ( _inOutPipeServer ) } ;
180+ if ( _outPipeServer != null )
171181 {
172- connectionTasks . Add ( WaitForConnectionAsync ( this . outPipeServer ) ) ;
182+ connectionTasks . Add ( WaitForConnectionAsync ( _outPipeServer ) ) ;
173183 }
174184
175185 await Task . WhenAll ( connectionTasks ) ;
176- this . OnClientConnect ( new NamedPipeServerChannel ( this . inOutPipeServer , this . outPipeServer , this . logger ) ) ;
186+ OnClientConnect ( new NamedPipeServerChannel ( _inOutPipeServer , _outPipeServer , _logger ) ) ;
177187 }
178188 catch ( Exception e )
179189 {
180- this . logger . WriteException (
190+ _logger . WriteException (
181191 "An unhandled exception occurred while listening for a named pipe client connection" ,
182192 e ) ;
183193
@@ -188,11 +198,7 @@ private void ListenForConnection()
188198
189199 private static async Task WaitForConnectionAsync ( NamedPipeServerStream pipeServerStream )
190200 {
191- #if CoreCLR
192201 await pipeServerStream . WaitForConnectionAsync ( ) ;
193- #else
194- await Task . Factory . FromAsync ( pipeServerStream . BeginWaitForConnection , pipeServerStream . EndWaitForConnection , null ) ;
195- #endif
196202 await pipeServerStream . FlushAsync ( ) ;
197203 }
198204 }
0 commit comments