@@ -20,28 +20,29 @@ namespace Microsoft.PowerShell.EditorServices.Protocol.MessageProtocol.Channel
20
20
public class NamedPipeServerListener : ServerListenerBase < NamedPipeServerChannel >
21
21
{
22
22
// 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 ;
24
24
25
25
// In .NET Framework, NamedPipeServerStream has a constructor that takes in a PipeSecurity object. We will use reflection to call the constructor,
26
26
// since .NET Framework doesn't have the `CurrentUserOnly` PipeOption.
27
27
// 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 =
29
29
typeof ( NamedPipeServerStream ) . GetConstructor ( new [ ] { typeof ( string ) , typeof ( PipeDirection ) , typeof ( int ) , typeof ( PipeTransmissionMode ) , typeof ( PipeOptions ) , typeof ( int ) , typeof ( int ) , typeof ( PipeSecurity ) } ) ;
30
30
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 ;
36
37
37
38
public NamedPipeServerListener (
38
39
MessageProtocolType messageProtocolType ,
39
40
string inOutPipeName ,
40
41
ILogger logger )
41
42
: base ( messageProtocolType )
42
43
{
43
- this . logger = logger ;
44
- this . inOutPipeName = inOutPipeName ;
44
+ _logger = logger ;
45
+ _inOutPipeName = inOutPipeName ;
45
46
}
46
47
47
48
public NamedPipeServerListener (
@@ -51,88 +52,21 @@ public NamedPipeServerListener(
51
52
ILogger logger )
52
53
: base ( messageProtocolType )
53
54
{
54
- this . logger = logger ;
55
- this . inOutPipeName = inPipeName ;
56
- this . outPipeName = outPipeName ;
55
+ _logger = logger ;
56
+ _inOutPipeName = inPipeName ;
57
+ _outPipeName = outPipeName ;
57
58
}
58
59
59
60
public override void Start ( )
60
61
{
61
62
try
62
63
{
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 ) ;
131
65
ListenForConnection ( ) ;
132
66
}
133
67
catch ( IOException e )
134
68
{
135
- this . logger . Write (
69
+ _logger . Write (
136
70
LogLevel . Verbose ,
137
71
"Named pipe server failed to start due to exception:\r \n \r \n " + e . Message ) ;
138
72
@@ -142,22 +76,98 @@ public override void Start()
142
76
143
77
public override void Stop ( )
144
78
{
145
- if ( this . inOutPipeServer != null )
79
+ if ( _inOutPipeServer != null )
146
80
{
147
- this . logger . Write ( LogLevel . Verbose , "Named pipe server shutting down..." ) ;
81
+ _logger . Write ( LogLevel . Verbose , "Named pipe server shutting down..." ) ;
148
82
149
- this . inOutPipeServer . Dispose ( ) ;
83
+ _inOutPipeServer . Dispose ( ) ;
150
84
151
- this . logger . Write ( LogLevel . Verbose , "Named pipe server has been disposed." ) ;
85
+ _logger . Write ( LogLevel . Verbose , "Named pipe server has been disposed." ) ;
152
86
}
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 )
154
105
{
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
156
125
157
- this . outPipeServer . Dispose ( ) ;
126
+ PipeSecurity pipeSecurity = new PipeSecurity ( ) ;
158
127
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 ) ) ;
160
144
}
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
+ } ) ;
161
171
}
162
172
163
173
private void ListenForConnection ( )
@@ -166,18 +176,18 @@ private void ListenForConnection()
166
176
{
167
177
try
168
178
{
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 )
171
181
{
172
- connectionTasks . Add ( WaitForConnectionAsync ( this . outPipeServer ) ) ;
182
+ connectionTasks . Add ( WaitForConnectionAsync ( _outPipeServer ) ) ;
173
183
}
174
184
175
185
await Task . WhenAll ( connectionTasks ) ;
176
- this . OnClientConnect ( new NamedPipeServerChannel ( this . inOutPipeServer , this . outPipeServer , this . logger ) ) ;
186
+ OnClientConnect ( new NamedPipeServerChannel ( _inOutPipeServer , _outPipeServer , _logger ) ) ;
177
187
}
178
188
catch ( Exception e )
179
189
{
180
- this . logger . WriteException (
190
+ _logger . WriteException (
181
191
"An unhandled exception occurred while listening for a named pipe client connection" ,
182
192
e ) ;
183
193
@@ -188,11 +198,7 @@ private void ListenForConnection()
188
198
189
199
private static async Task WaitForConnectionAsync ( NamedPipeServerStream pipeServerStream )
190
200
{
191
- #if CoreCLR
192
201
await pipeServerStream . WaitForConnectionAsync ( ) ;
193
- #else
194
- await Task . Factory . FromAsync ( pipeServerStream . BeginWaitForConnection , pipeServerStream . EndWaitForConnection , null ) ;
195
- #endif
196
202
await pipeServerStream . FlushAsync ( ) ;
197
203
}
198
204
}
0 commit comments