blob: 593bb3a66a60c4352905f0d4813c08b52a30e32e [file] [log] [blame]
Roger Meier3bef8c22012-10-06 06:58:00 +00001(*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *)
19unit Thrift.Transport.Pipes;
20
21{$WARN SYMBOL_PLATFORM OFF}
22
23interface
24
25uses
Jens Geyer06045cf2013-03-27 20:26:25 +020026 Windows, SysUtils, Math, AccCtrl, AclAPI, SyncObjs,
Roger Meier3bef8c22012-10-06 06:58:00 +000027 Thrift.Transport,
Jens Geyere9651362014-03-20 22:46:17 +020028 Thrift.Utils,
Roger Meier3bef8c22012-10-06 06:58:00 +000029 Thrift.Stream;
30
31const
Jens Geyer3e8d9272014-09-14 20:10:40 +020032 DEFAULT_THRIFT_PIPE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT deprecated 'use DEFAULT_THRIFT_TIMEOUT';
Roger Meier3bef8c22012-10-06 06:58:00 +000033
34
Jens Geyere9651362014-03-20 22:46:17 +020035
Roger Meier3bef8c22012-10-06 06:58:00 +000036type
Roger Meier79655fb2012-10-20 20:59:41 +000037 //--- Pipe Streams ---
Roger Meier3bef8c22012-10-06 06:58:00 +000038
39
Jens Geyer06045cf2013-03-27 20:26:25 +020040 TPipeStreamBase = class( TThriftStreamImpl)
Roger Meier79655fb2012-10-20 20:59:41 +000041 strict protected
42 FPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +000043 FTimeout : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +020044 FOverlapped : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +000045
Roger Meier3bef8c22012-10-06 06:58:00 +000046 procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;
47 function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;
Roger Meier79655fb2012-10-20 20:59:41 +000048 //procedure Open; override; - see derived classes
Roger Meier3bef8c22012-10-06 06:58:00 +000049 procedure Close; override;
50 procedure Flush; override;
51
Jens Geyere9651362014-03-20 22:46:17 +020052 function ReadDirect( var buffer: TBytes; offset: Integer; count: Integer): Integer;
53 function ReadOverlapped( var buffer: TBytes; offset: Integer; count: Integer): Integer;
54 procedure WriteDirect( const buffer: TBytes; offset: Integer; count: Integer);
55 procedure WriteOverlapped( const buffer: TBytes; offset: Integer; count: Integer);
56
Roger Meier3bef8c22012-10-06 06:58:00 +000057 function IsOpen: Boolean; override;
58 function ToArray: TBytes; override;
59 public
Jens Geyer3e8d9272014-09-14 20:10:40 +020060 constructor Create( aEnableOverlapped : Boolean; const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT);
Roger Meier3bef8c22012-10-06 06:58:00 +000061 destructor Destroy; override;
62 end;
63
64
Jens Geyer06045cf2013-03-27 20:26:25 +020065 TNamedPipeStreamImpl = class sealed( TPipeStreamBase)
Jens Geyere9651362014-03-20 22:46:17 +020066 strict private
Roger Meier79655fb2012-10-20 20:59:41 +000067 FPipeName : string;
68 FShareMode : DWORD;
69 FSecurityAttribs : PSecurityAttributes;
Roger Meier3bef8c22012-10-06 06:58:00 +000070
Jens Geyere9651362014-03-20 22:46:17 +020071 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +000072 procedure Open; override;
73
74 public
75 constructor Create( const aPipeName : string;
Jens Geyere9651362014-03-20 22:46:17 +020076 const aEnableOverlapped : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +000077 const aShareMode: DWORD = 0;
78 const aSecurityAttributes: PSecurityAttributes = nil;
Jens Geyer3e8d9272014-09-14 20:10:40 +020079 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); overload;
Roger Meier79655fb2012-10-20 20:59:41 +000080 end;
81
82
Jens Geyer06045cf2013-03-27 20:26:25 +020083 THandlePipeStreamImpl = class sealed( TPipeStreamBase)
Jens Geyere9651362014-03-20 22:46:17 +020084 strict private
Roger Meier79655fb2012-10-20 20:59:41 +000085 FSrcHandle : THandle;
86
Jens Geyere9651362014-03-20 22:46:17 +020087 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +000088 procedure Open; override;
89
90 public
Jens Geyere9651362014-03-20 22:46:17 +020091 constructor Create( const aPipeHandle : THandle;
92 const aOwnsHandle, aEnableOverlapped : Boolean;
Jens Geyer3e8d9272014-09-14 20:10:40 +020093 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); overload;
Roger Meier79655fb2012-10-20 20:59:41 +000094 destructor Destroy; override;
95 end;
96
97
98 //--- Pipe Transports ---
99
100
Jens Geyer06045cf2013-03-27 20:26:25 +0200101 IPipeTransport = interface( IStreamTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000102 ['{5E05CC85-434F-428F-BFB2-856A168B5558}']
103 end;
104
105
Jens Geyer06045cf2013-03-27 20:26:25 +0200106 TPipeTransportBase = class( TStreamTransportImpl, IPipeTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000107 public
108 // ITransport
109 function GetIsOpen: Boolean; override;
110 procedure Open; override;
111 procedure Close; override;
112 end;
113
114
Jens Geyer06045cf2013-03-27 20:26:25 +0200115 TNamedPipeTransportClientEndImpl = class( TPipeTransportBase)
Roger Meier79655fb2012-10-20 20:59:41 +0000116 public
Roger Meier3bef8c22012-10-06 06:58:00 +0000117 // Named pipe constructors
Jens Geyere9651362014-03-20 22:46:17 +0200118 constructor Create( aPipe : THandle; aOwnsHandle : Boolean;
119 const aTimeOut : DWORD); overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000120 constructor Create( const aPipeName : string;
121 const aShareMode: DWORD = 0;
122 const aSecurityAttributes: PSecurityAttributes = nil;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200123 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000124 end;
125
126
Jens Geyer06045cf2013-03-27 20:26:25 +0200127 TNamedPipeTransportServerEndImpl = class( TNamedPipeTransportClientEndImpl)
Roger Meier79655fb2012-10-20 20:59:41 +0000128 strict private
129 FHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000130 public
Roger Meier79655fb2012-10-20 20:59:41 +0000131 // ITransport
132 procedure Close; override;
Jens Geyere9651362014-03-20 22:46:17 +0200133 constructor Create( aPipe : THandle; aOwnsHandle : Boolean;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200134 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); reintroduce;
Roger Meier79655fb2012-10-20 20:59:41 +0000135 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000136
Roger Meier79655fb2012-10-20 20:59:41 +0000137
Jens Geyer06045cf2013-03-27 20:26:25 +0200138 TAnonymousPipeTransportImpl = class( TPipeTransportBase)
Roger Meier79655fb2012-10-20 20:59:41 +0000139 public
Roger Meier3bef8c22012-10-06 06:58:00 +0000140 // Anonymous pipe constructor
141 constructor Create( const aPipeRead, aPipeWrite : THandle; aOwnsHandles : Boolean); overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000142 end;
143
144
Roger Meier79655fb2012-10-20 20:59:41 +0000145 //--- Server Transports ---
146
147
Jens Geyer06045cf2013-03-27 20:26:25 +0200148 IAnonymousPipeServerTransport = interface( IServerTransport)
Roger Meier3bef8c22012-10-06 06:58:00 +0000149 ['{7AEE6793-47B9-4E49-981A-C39E9108E9AD}']
150 // Server side anonymous pipe ends
Roger Meier79655fb2012-10-20 20:59:41 +0000151 function ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000152 function WriteHandle : THandle;
153 // Client side anonymous pipe ends
154 function ClientAnonRead : THandle;
155 function ClientAnonWrite : THandle;
156 end;
157
158
Jens Geyer06045cf2013-03-27 20:26:25 +0200159 INamedPipeServerTransport = interface( IServerTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000160 ['{9DF9EE48-D065-40AF-8F67-D33037D3D960}']
161 function Handle : THandle;
162 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000163
Roger Meier79655fb2012-10-20 20:59:41 +0000164
Jens Geyer06045cf2013-03-27 20:26:25 +0200165 TPipeServerTransportBase = class( TServerTransportImpl)
Jens Geyere9651362014-03-20 22:46:17 +0200166 strict protected
167 FStopServer : TEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200168 procedure InternalClose; virtual; abstract;
Jens Geyere9651362014-03-20 22:46:17 +0200169 function QueryStopServer : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000170 public
Jens Geyere9651362014-03-20 22:46:17 +0200171 constructor Create;
172 destructor Destroy; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000173 procedure Listen; override;
Jens Geyer06045cf2013-03-27 20:26:25 +0200174 procedure Close; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000175 end;
176
177
Jens Geyer06045cf2013-03-27 20:26:25 +0200178 TAnonymousPipeServerTransportImpl = class( TPipeServerTransportBase, IAnonymousPipeServerTransport)
Jens Geyere9651362014-03-20 22:46:17 +0200179 strict private
Roger Meier79655fb2012-10-20 20:59:41 +0000180 FBufSize : DWORD;
181
182 // Server side anonymous pipe handles
183 FReadHandle,
Roger Meier3bef8c22012-10-06 06:58:00 +0000184 FWriteHandle : THandle;
185
186 //Client side anonymous pipe handles
187 FClientAnonRead,
188 FClientAnonWrite : THandle;
189
190 protected
Jens Geyer01640402013-09-25 21:12:21 +0200191 function Accept(const fnAccepting: TProc): ITransport; override;
Roger Meier3bef8c22012-10-06 06:58:00 +0000192
Roger Meier3bef8c22012-10-06 06:58:00 +0000193 function CreateAnonPipe : Boolean;
194
Jens Geyer06045cf2013-03-27 20:26:25 +0200195 // IAnonymousPipeServerTransport
Roger Meier79655fb2012-10-20 20:59:41 +0000196 function ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000197 function WriteHandle : THandle;
198 function ClientAnonRead : THandle;
199 function ClientAnonWrite : THandle;
200
Jens Geyer06045cf2013-03-27 20:26:25 +0200201 procedure InternalClose; override;
202
Roger Meier3bef8c22012-10-06 06:58:00 +0000203 public
Roger Meier79655fb2012-10-20 20:59:41 +0000204 constructor Create( aBufsize : Cardinal = 4096);
Roger Meier3bef8c22012-10-06 06:58:00 +0000205 end;
206
207
Jens Geyer06045cf2013-03-27 20:26:25 +0200208 TNamedPipeServerTransportImpl = class( TPipeServerTransportBase, INamedPipeServerTransport)
Jens Geyere9651362014-03-20 22:46:17 +0200209 strict private
Roger Meier79655fb2012-10-20 20:59:41 +0000210 FPipeName : string;
211 FMaxConns : DWORD;
212 FBufSize : DWORD;
Jens Geyer0b20cc82013-03-07 20:47:01 +0100213 FTimeout : DWORD;
Jens Geyer06045cf2013-03-27 20:26:25 +0200214 FHandle : THandle;
215 FConnected : Boolean;
Jens Geyer01640402013-09-25 21:12:21 +0200216
217
Jens Geyere9651362014-03-20 22:46:17 +0200218 strict protected
Jens Geyer01640402013-09-25 21:12:21 +0200219 function Accept(const fnAccepting: TProc): ITransport; override;
Jens Geyer06045cf2013-03-27 20:26:25 +0200220 function CreateNamedPipe : THandle;
221 function CreateTransportInstance : ITransport;
Roger Meier79655fb2012-10-20 20:59:41 +0000222
Jens Geyer06045cf2013-03-27 20:26:25 +0200223 // INamedPipeServerTransport
Roger Meier79655fb2012-10-20 20:59:41 +0000224 function Handle : THandle;
Jens Geyer06045cf2013-03-27 20:26:25 +0200225 procedure InternalClose; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000226
227 public
228 constructor Create( aPipename : string; aBufsize : Cardinal = 4096;
Jens Geyer0b20cc82013-03-07 20:47:01 +0100229 aMaxConns : Cardinal = PIPE_UNLIMITED_INSTANCES;
Jens Geyer2ad6c302015-02-26 19:38:53 +0100230 aTimeOut : Cardinal = INFINITE);
Roger Meier79655fb2012-10-20 20:59:41 +0000231 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000232
233
234implementation
235
236
Roger Meier79655fb2012-10-20 20:59:41 +0000237procedure ClosePipeHandle( var hPipe : THandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000238begin
Roger Meier79655fb2012-10-20 20:59:41 +0000239 if hPipe <> INVALID_HANDLE_VALUE
240 then try
241 CloseHandle( hPipe);
242 finally
243 hPipe := INVALID_HANDLE_VALUE;
244 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000245end;
246
247
Roger Meier79655fb2012-10-20 20:59:41 +0000248function DuplicatePipeHandle( const hSource : THandle) : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000249begin
Roger Meier79655fb2012-10-20 20:59:41 +0000250 if not DuplicateHandle( GetCurrentProcess, hSource,
251 GetCurrentProcess, @result,
252 0, FALSE, DUPLICATE_SAME_ACCESS)
253 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
254 'DuplicateHandle: '+SysErrorMessage(GetLastError));
Roger Meier3bef8c22012-10-06 06:58:00 +0000255end;
256
257
Roger Meier79655fb2012-10-20 20:59:41 +0000258
Jens Geyer06045cf2013-03-27 20:26:25 +0200259{ TPipeStreamBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000260
261
Jens Geyere9651362014-03-20 22:46:17 +0200262constructor TPipeStreamBase.Create( aEnableOverlapped : Boolean;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200263 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT);
Roger Meier79655fb2012-10-20 20:59:41 +0000264begin
265 inherited Create;
Jens Geyere9651362014-03-20 22:46:17 +0200266 ASSERT( aTimeout > 0);
267 FPipe := INVALID_HANDLE_VALUE;
268 FTimeout := aTimeOut;
269 FOverlapped := aEnableOverlapped;
Roger Meier79655fb2012-10-20 20:59:41 +0000270end;
271
272
Jens Geyer06045cf2013-03-27 20:26:25 +0200273destructor TPipeStreamBase.Destroy;
Roger Meier3bef8c22012-10-06 06:58:00 +0000274begin
275 try
276 Close;
277 finally
278 inherited Destroy;
279 end;
280end;
281
282
Jens Geyer06045cf2013-03-27 20:26:25 +0200283procedure TPipeStreamBase.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000284begin
Roger Meier79655fb2012-10-20 20:59:41 +0000285 ClosePipeHandle( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000286end;
287
288
Jens Geyer06045cf2013-03-27 20:26:25 +0200289procedure TPipeStreamBase.Flush;
Roger Meier3bef8c22012-10-06 06:58:00 +0000290begin
291 // nothing to do
292end;
293
294
Jens Geyer06045cf2013-03-27 20:26:25 +0200295function TPipeStreamBase.IsOpen: Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000296begin
297 result := (FPipe <> INVALID_HANDLE_VALUE);
298end;
299
300
Jens Geyer06045cf2013-03-27 20:26:25 +0200301procedure TPipeStreamBase.Write(const buffer: TBytes; offset, count: Integer);
Jens Geyere9651362014-03-20 22:46:17 +0200302begin
303 if FOverlapped
304 then WriteOverlapped( buffer, offset, count)
305 else WriteDirect( buffer, offset, count);
306end;
307
308
309function TPipeStreamBase.Read( var buffer: TBytes; offset, count: Integer): Integer;
310begin
311 if FOverlapped
312 then result := ReadOverlapped( buffer, offset, count)
313 else result := ReadDirect( buffer, offset, count);
314end;
315
316
317procedure TPipeStreamBase.WriteDirect(const buffer: TBytes; offset, count: Integer);
Roger Meier3bef8c22012-10-06 06:58:00 +0000318var cbWritten : DWORD;
319begin
320 if not IsOpen
321 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
322 'Called write on non-open pipe');
323
324 if not WriteFile( FPipe, buffer[offset], count, cbWritten, nil)
325 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
326 'Write to pipe failed');
327end;
328
329
Jens Geyere9651362014-03-20 22:46:17 +0200330function TPipeStreamBase.ReadDirect( var buffer: TBytes; offset, count: Integer): Integer;
Roger Meier79655fb2012-10-20 20:59:41 +0000331var cbRead, dwErr : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000332 bytes, retries : LongInt;
333 bOk : Boolean;
334const INTERVAL = 10; // ms
335begin
336 if not IsOpen
337 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
338 'Called read on non-open pipe');
339
340 // MSDN: Handle can be a handle to a named pipe instance,
341 // or it can be a handle to the read end of an anonymous pipe,
342 // The handle must have GENERIC_READ access to the pipe.
343 if FTimeOut <> INFINITE then begin
344 retries := Max( 1, Round( 1.0 * FTimeOut / INTERVAL));
345 while TRUE do begin
346 if IsOpen
347 and PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil)
348 and (bytes > 0)
349 then Break; // there are data
350
Roger Meier79655fb2012-10-20 20:59:41 +0000351 dwErr := GetLastError;
Jens Geyer06045cf2013-03-27 20:26:25 +0200352 if (dwErr = ERROR_INVALID_HANDLE)
353 or (dwErr = ERROR_BROKEN_PIPE)
Roger Meier79655fb2012-10-20 20:59:41 +0000354 or (dwErr = ERROR_PIPE_NOT_CONNECTED)
355 then begin
356 result := 0; // other side closed the pipe
357 Exit;
358 end;
359
Roger Meier3bef8c22012-10-06 06:58:00 +0000360 Dec( retries);
361 if retries > 0
362 then Sleep( INTERVAL)
363 else raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
364 'Pipe read timed out');
365 end;
366 end;
367
368 // read the data (or block INFINITE-ly)
369 bOk := ReadFile( FPipe, buffer[offset], count, cbRead, nil);
370 if (not bOk) and (GetLastError() <> ERROR_MORE_DATA)
371 then result := 0 // No more data, possibly because client disconnected.
372 else result := cbRead;
373end;
374
375
Jens Geyere9651362014-03-20 22:46:17 +0200376procedure TPipeStreamBase.WriteOverlapped(const buffer: TBytes; offset, count: Integer);
377var cbWritten, dwWait, dwError : DWORD;
378 overlapped : IOverlappedHelper;
379begin
380 if not IsOpen
381 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
382 'Called write on non-open pipe');
383
384 overlapped := TOverlappedHelperImpl.Create;
385
386 if not WriteFile( FPipe, buffer[offset], count, cbWritten, overlapped.OverlappedPtr)
387 then begin
388 dwError := GetLastError;
389 case dwError of
390 ERROR_IO_PENDING : begin
391 dwWait := overlapped.WaitFor(FTimeout);
392
393 if (dwWait = WAIT_TIMEOUT)
394 then raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
395 'Pipe write timed out');
396
397 if (dwWait <> WAIT_OBJECT_0)
398 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbWritten, TRUE)
399 then raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
400 'Pipe write error');
401 end;
402
403 else
404 raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
405 SysErrorMessage(dwError));
406 end;
407 end;
408
409 ASSERT( DWORD(count) = cbWritten);
410end;
411
412
413function TPipeStreamBase.ReadOverlapped( var buffer: TBytes; offset, count: Integer): Integer;
414var cbRead, dwWait, dwError : DWORD;
415 bOk : Boolean;
416 overlapped : IOverlappedHelper;
417begin
418 if not IsOpen
419 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
420 'Called read on non-open pipe');
421
422 overlapped := TOverlappedHelperImpl.Create;
423
424 // read the data
425 bOk := ReadFile( FPipe, buffer[offset], count, cbRead, overlapped.OverlappedPtr);
426 if not bOk then begin
427 dwError := GetLastError;
428 case dwError of
429 ERROR_IO_PENDING : begin
430 dwWait := overlapped.WaitFor(FTimeout);
431
432 if (dwWait = WAIT_TIMEOUT)
433 then raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
434 'Pipe read timed out');
435
436 if (dwWait <> WAIT_OBJECT_0)
437 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbRead, TRUE)
438 then raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
439 'Pipe read error');
440 end;
441
442 else
443 raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
444 SysErrorMessage(dwError));
445 end;
446 end;
447
448 ASSERT( cbRead > 0); // see TTransportImpl.ReadAll()
449 ASSERT( cbRead = DWORD(count));
450 result := cbRead;
451end;
452
453
Jens Geyer06045cf2013-03-27 20:26:25 +0200454function TPipeStreamBase.ToArray: TBytes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000455var bytes : LongInt;
456begin
457 SetLength( result, 0);
458 bytes := 0;
459
460 if IsOpen
461 and PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil)
462 and (bytes > 0)
463 then begin
464 SetLength( result, bytes);
465 Read( result, 0, bytes);
466 end;
467end;
468
469
Roger Meier79655fb2012-10-20 20:59:41 +0000470{ TNamedPipeStreamImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000471
472
Jens Geyere9651362014-03-20 22:46:17 +0200473constructor TNamedPipeStreamImpl.Create( const aPipeName : string;
474 const aEnableOverlapped : Boolean;
475 const aShareMode: DWORD;
Roger Meier79655fb2012-10-20 20:59:41 +0000476 const aSecurityAttributes: PSecurityAttributes;
477 const aTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000478begin
Jens Geyere9651362014-03-20 22:46:17 +0200479 inherited Create( aEnableOverlapped, aTimeout);
Roger Meier79655fb2012-10-20 20:59:41 +0000480
481 FPipeName := aPipeName;
482 FShareMode := aShareMode;
483 FSecurityAttribs := aSecurityAttributes;
484
485 if Copy(FPipeName,1,2) <> '\\'
486 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
Roger Meier3bef8c22012-10-06 06:58:00 +0000487end;
488
489
Roger Meier79655fb2012-10-20 20:59:41 +0000490procedure TNamedPipeStreamImpl.Open;
491var hPipe : THandle;
Roger Meier79655fb2012-10-20 20:59:41 +0000492begin
493 if IsOpen then Exit;
494
495 // open that thingy
496
497 if not WaitNamedPipe( PChar(FPipeName), FTimeout)
498 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
499 'Unable to open pipe, '+SysErrorMessage(GetLastError));
500
501 hPipe := CreateFile( PChar( FPipeName),
502 GENERIC_READ or GENERIC_WRITE,
503 FShareMode, // sharing
504 FSecurityAttribs, // security attributes
505 OPEN_EXISTING, // opens existing pipe
Jens Geyere9651362014-03-20 22:46:17 +0200506 FILE_FLAG_OVERLAPPED or FILE_FLAG_WRITE_THROUGH, // async+fast, please
Roger Meier79655fb2012-10-20 20:59:41 +0000507 0); // no template file
508
509 if hPipe = INVALID_HANDLE_VALUE
510 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
511 'Unable to open pipe, '+SysErrorMessage(GetLastError));
512
Roger Meier79655fb2012-10-20 20:59:41 +0000513 // everything fine
514 FPipe := hPipe;
515end;
516
517
518{ THandlePipeStreamImpl }
519
520
Jens Geyere9651362014-03-20 22:46:17 +0200521constructor THandlePipeStreamImpl.Create( const aPipeHandle : THandle;
522 const aOwnsHandle, aEnableOverlapped : Boolean;
523 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000524begin
Jens Geyere9651362014-03-20 22:46:17 +0200525 inherited Create( aEnableOverlapped, aTimeOut);
Roger Meier79655fb2012-10-20 20:59:41 +0000526
527 if aOwnsHandle
528 then FSrcHandle := aPipeHandle
529 else FSrcHandle := DuplicatePipeHandle( aPipeHandle);
530
531 Open;
532end;
533
534
535destructor THandlePipeStreamImpl.Destroy;
536begin
537 try
538 ClosePipeHandle( FSrcHandle);
539 finally
540 inherited Destroy;
541 end;
542end;
543
544
545procedure THandlePipeStreamImpl.Open;
546begin
547 if not IsOpen
548 then FPipe := DuplicatePipeHandle( FSrcHandle);
549end;
550
551
Jens Geyer06045cf2013-03-27 20:26:25 +0200552{ TPipeTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000553
554
Jens Geyer06045cf2013-03-27 20:26:25 +0200555function TPipeTransportBase.GetIsOpen: Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000556begin
Jens Geyer0b20cc82013-03-07 20:47:01 +0100557 result := (FInputStream <> nil) and (FInputStream.IsOpen)
558 and (FOutputStream <> nil) and (FOutputStream.IsOpen);
Roger Meier79655fb2012-10-20 20:59:41 +0000559end;
560
561
Jens Geyer06045cf2013-03-27 20:26:25 +0200562procedure TPipeTransportBase.Open;
Roger Meier79655fb2012-10-20 20:59:41 +0000563begin
564 FInputStream.Open;
565 FOutputStream.Open;
566end;
567
568
Jens Geyer06045cf2013-03-27 20:26:25 +0200569procedure TPipeTransportBase.Close;
Roger Meier79655fb2012-10-20 20:59:41 +0000570begin
571 FInputStream.Close;
572 FOutputStream.Close;
573end;
574
575
Jens Geyer06045cf2013-03-27 20:26:25 +0200576{ TNamedPipeTransportClientEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000577
578
Jens Geyer06045cf2013-03-27 20:26:25 +0200579constructor TNamedPipeTransportClientEndImpl.Create( const aPipeName : string; const aShareMode: DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000580 const aSecurityAttributes: PSecurityAttributes;
581 const aTimeOut : DWORD);
582// Named pipe constructor
583begin
Roger Meier79655fb2012-10-20 20:59:41 +0000584 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200585 FInputStream := TNamedPipeStreamImpl.Create( aPipeName, TRUE, aShareMode, aSecurityAttributes, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000586 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000587end;
588
589
Jens Geyere9651362014-03-20 22:46:17 +0200590constructor TNamedPipeTransportClientEndImpl.Create( aPipe : THandle; aOwnsHandle : Boolean;
591 const aTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000592// Named pipe constructor
593begin
Roger Meier79655fb2012-10-20 20:59:41 +0000594 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200595 FInputStream := THandlePipeStreamImpl.Create( aPipe, TRUE, aOwnsHandle, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000596 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000597end;
598
599
Jens Geyer06045cf2013-03-27 20:26:25 +0200600{ TNamedPipeTransportServerEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000601
602
Jens Geyere9651362014-03-20 22:46:17 +0200603constructor TNamedPipeTransportServerEndImpl.Create( aPipe : THandle; aOwnsHandle : Boolean;
604 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000605// Named pipe constructor
Roger Meier3bef8c22012-10-06 06:58:00 +0000606begin
Roger Meier79655fb2012-10-20 20:59:41 +0000607 FHandle := DuplicatePipeHandle( aPipe);
Jens Geyere9651362014-03-20 22:46:17 +0200608 inherited Create( aPipe, aOwnsHandle, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000609end;
610
611
Jens Geyer06045cf2013-03-27 20:26:25 +0200612procedure TNamedPipeTransportServerEndImpl.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000613begin
Roger Meier79655fb2012-10-20 20:59:41 +0000614 FlushFileBuffers( FHandle);
615 DisconnectNamedPipe( FHandle); // force client off the pipe
616 ClosePipeHandle( FHandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000617
Roger Meier79655fb2012-10-20 20:59:41 +0000618 inherited Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000619end;
620
621
Jens Geyer06045cf2013-03-27 20:26:25 +0200622{ TAnonymousPipeTransportImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000623
624
Jens Geyer06045cf2013-03-27 20:26:25 +0200625constructor TAnonymousPipeTransportImpl.Create( const aPipeRead, aPipeWrite : THandle; aOwnsHandles : Boolean);
Roger Meier3bef8c22012-10-06 06:58:00 +0000626// Anonymous pipe constructor
627begin
Roger Meier79655fb2012-10-20 20:59:41 +0000628 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200629 // overlapped is not supported with AnonPipes, see MSDN
630 FInputStream := THandlePipeStreamImpl.Create( aPipeRead, aOwnsHandles, FALSE);
631 FOutputStream := THandlePipeStreamImpl.Create( aPipeWrite, aOwnsHandles, FALSE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000632end;
633
634
Jens Geyer06045cf2013-03-27 20:26:25 +0200635{ TPipeServerTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000636
637
Jens Geyere9651362014-03-20 22:46:17 +0200638constructor TPipeServerTransportBase.Create;
639begin
640 inherited Create;
641 FStopServer := TEvent.Create(nil,TRUE,FALSE,''); // manual reset
642end;
643
644
645destructor TPipeServerTransportBase.Destroy;
646begin
647 try
648 FreeAndNil( FStopServer);
649 finally
650 inherited Destroy;
651 end;
652end;
653
654
655function TPipeServerTransportBase.QueryStopServer : Boolean;
656begin
657 result := (FStopServer = nil)
658 or (FStopServer.WaitFor(0) <> wrTimeout);
659end;
660
661
Jens Geyer06045cf2013-03-27 20:26:25 +0200662procedure TPipeServerTransportBase.Listen;
Roger Meier3bef8c22012-10-06 06:58:00 +0000663begin
Jens Geyere9651362014-03-20 22:46:17 +0200664 FStopServer.ResetEvent;
Roger Meier3bef8c22012-10-06 06:58:00 +0000665end;
666
667
Jens Geyer06045cf2013-03-27 20:26:25 +0200668procedure TPipeServerTransportBase.Close;
669begin
Jens Geyere9651362014-03-20 22:46:17 +0200670 FStopServer.SetEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200671 InternalClose;
672end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000673
674
Jens Geyer06045cf2013-03-27 20:26:25 +0200675{ TAnonymousPipeServerTransportImpl }
676
677
678constructor TAnonymousPipeServerTransportImpl.Create( aBufsize : Cardinal);
Roger Meier3bef8c22012-10-06 06:58:00 +0000679// Anonymous pipe CTOR
680begin
681 inherited Create;
Roger Meier3bef8c22012-10-06 06:58:00 +0000682 FBufsize := aBufSize;
Roger Meier79655fb2012-10-20 20:59:41 +0000683 FReadHandle := INVALID_HANDLE_VALUE;
Roger Meier3bef8c22012-10-06 06:58:00 +0000684 FWriteHandle := INVALID_HANDLE_VALUE;
685 FClientAnonRead := INVALID_HANDLE_VALUE;
686 FClientAnonWrite := INVALID_HANDLE_VALUE;
687
688 // The anonymous pipe needs to be created first so that the server can
689 // pass the handles on to the client before the serve (acceptImpl)
690 // blocking call.
691 if not CreateAnonPipe
692 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
693 ClassName+'.Create() failed');
694end;
695
696
Jens Geyer01640402013-09-25 21:12:21 +0200697function TAnonymousPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Roger Meier3bef8c22012-10-06 06:58:00 +0000698var buf : Byte;
699 br : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000700begin
Jens Geyer01640402013-09-25 21:12:21 +0200701 if Assigned(fnAccepting)
702 then fnAccepting();
703
Roger Meier79655fb2012-10-20 20:59:41 +0000704 // This 0-byte read serves merely as a blocking call.
705 if not ReadFile( FReadHandle, buf, 0, br, nil)
706 and (GetLastError() <> ERROR_MORE_DATA)
707 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
708 'TServerPipe unable to initiate pipe communication');
Jens Geyer06045cf2013-03-27 20:26:25 +0200709
710 // create the transport impl
711 result := TAnonymousPipeTransportImpl.Create( FReadHandle, FWriteHandle, FALSE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000712end;
713
714
Jens Geyer06045cf2013-03-27 20:26:25 +0200715procedure TAnonymousPipeServerTransportImpl.InternalClose;
Roger Meier3bef8c22012-10-06 06:58:00 +0000716begin
Roger Meier79655fb2012-10-20 20:59:41 +0000717 ClosePipeHandle( FReadHandle);
718 ClosePipeHandle( FWriteHandle);
719 ClosePipeHandle( FClientAnonRead);
720 ClosePipeHandle( FClientAnonWrite);
Roger Meier3bef8c22012-10-06 06:58:00 +0000721end;
722
723
Jens Geyer06045cf2013-03-27 20:26:25 +0200724function TAnonymousPipeServerTransportImpl.ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000725begin
Roger Meier79655fb2012-10-20 20:59:41 +0000726 result := FReadHandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000727end;
728
729
Jens Geyer06045cf2013-03-27 20:26:25 +0200730function TAnonymousPipeServerTransportImpl.WriteHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000731begin
732 result := FWriteHandle;
733end;
734
735
Jens Geyer06045cf2013-03-27 20:26:25 +0200736function TAnonymousPipeServerTransportImpl.ClientAnonRead : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000737begin
738 result := FClientAnonRead;
739end;
740
741
Jens Geyer06045cf2013-03-27 20:26:25 +0200742function TAnonymousPipeServerTransportImpl.ClientAnonWrite : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000743begin
744 result := FClientAnonWrite;
745end;
746
747
Jens Geyer06045cf2013-03-27 20:26:25 +0200748function TAnonymousPipeServerTransportImpl.CreateAnonPipe : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000749var sd : PSECURITY_DESCRIPTOR;
750 sa : SECURITY_ATTRIBUTES; //TSecurityAttributes;
751 hCAR, hPipeW, hCAW, hPipe : THandle;
752begin
753 result := FALSE;
754
755 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
Jens Geyerb64a7742013-01-23 20:58:47 +0100756 try
757 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
758 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, nil, FALSE));
Roger Meier79655fb2012-10-20 20:59:41 +0000759
Jens Geyerb64a7742013-01-23 20:58:47 +0100760 sa.nLength := sizeof( sa);
761 sa.lpSecurityDescriptor := sd;
762 sa.bInheritHandle := TRUE; //allow passing handle to child
Roger Meier79655fb2012-10-20 20:59:41 +0000763
Jens Geyerb64a7742013-01-23 20:58:47 +0100764 if not CreatePipe( hCAR, hPipeW, @sa, FBufSize) then begin //create stdin pipe
Jens Geyer06045cf2013-03-27 20:26:25 +0200765 raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
766 'TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100767 Exit;
768 end;
769
770 if not CreatePipe( hPipe, hCAW, @sa, FBufSize) then begin //create stdout pipe
Jens Geyerb64a7742013-01-23 20:58:47 +0100771 CloseHandle( hCAR);
772 CloseHandle( hPipeW);
Jens Geyer06045cf2013-03-27 20:26:25 +0200773 raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
774 'TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100775 Exit;
776 end;
777
778 FClientAnonRead := hCAR;
779 FClientAnonWrite := hCAW;
780 FReadHandle := hPipe;
781 FWriteHandle := hPipeW;
782
783 result := TRUE;
Jens Geyerd5436f52014-10-03 19:50:38 +0200784
Jens Geyerb64a7742013-01-23 20:58:47 +0100785 finally
786 if sd <> nil then LocalFree( Cardinal(sd));
Roger Meier79655fb2012-10-20 20:59:41 +0000787 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000788end;
789
790
Jens Geyer06045cf2013-03-27 20:26:25 +0200791{ TNamedPipeServerTransportImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000792
793
Jens Geyer06045cf2013-03-27 20:26:25 +0200794constructor TNamedPipeServerTransportImpl.Create( aPipename : string; aBufsize, aMaxConns, aTimeOut : Cardinal);
Roger Meier79655fb2012-10-20 20:59:41 +0000795// Named Pipe CTOR
796begin
797 inherited Create;
Jens Geyere9651362014-03-20 22:46:17 +0200798 ASSERT( aTimeout > 0);
Jens Geyer06045cf2013-03-27 20:26:25 +0200799 FPipeName := aPipename;
800 FBufsize := aBufSize;
801 FMaxConns := Max( 1, Min( PIPE_UNLIMITED_INSTANCES, aMaxConns));
802 FHandle := INVALID_HANDLE_VALUE;
803 FTimeout := aTimeOut;
804 FConnected := FALSE;
Roger Meier79655fb2012-10-20 20:59:41 +0000805
806 if Copy(FPipeName,1,2) <> '\\'
807 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
808end;
809
810
Jens Geyer01640402013-09-25 21:12:21 +0200811function TNamedPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Jens Geyer06045cf2013-03-27 20:26:25 +0200812var dwError, dwWait, dwDummy : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +0200813 overlapped : IOverlappedHelper;
814 handles : array[0..1] of THandle;
Jens Geyer01640402013-09-25 21:12:21 +0200815begin
Jens Geyere9651362014-03-20 22:46:17 +0200816 overlapped := TOverlappedHelperImpl.Create;
Jens Geyer01640402013-09-25 21:12:21 +0200817
Jens Geyere9651362014-03-20 22:46:17 +0200818 ASSERT( not FConnected);
Jens Geyer2ad6c302015-02-26 19:38:53 +0100819 CreateNamedPipe;
Jens Geyere9651362014-03-20 22:46:17 +0200820 while not FConnected do begin
Jens Geyer2ad6c302015-02-26 19:38:53 +0100821
822 if QueryStopServer
823 then Abort;
Roger Meier79655fb2012-10-20 20:59:41 +0000824
Jens Geyere9651362014-03-20 22:46:17 +0200825 if Assigned(fnAccepting)
826 then fnAccepting();
Jens Geyer01640402013-09-25 21:12:21 +0200827
Jens Geyere9651362014-03-20 22:46:17 +0200828 // Wait for the client to connect; if it succeeds, the
829 // function returns a nonzero value. If the function returns
830 // zero, GetLastError should return ERROR_PIPE_CONNECTED.
831 if ConnectNamedPipe( Handle, overlapped.OverlappedPtr) then begin
832 FConnected := TRUE;
833 Break;
Jens Geyer01640402013-09-25 21:12:21 +0200834 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000835
Jens Geyere9651362014-03-20 22:46:17 +0200836 // ConnectNamedPipe() returns FALSE for OverlappedIO, even if connected.
837 // We have to check GetLastError() explicitly to find out
838 dwError := GetLastError;
839 case dwError of
840 ERROR_PIPE_CONNECTED : begin
841 FConnected := not QueryStopServer; // special case: pipe immediately connected
842 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000843
Jens Geyere9651362014-03-20 22:46:17 +0200844 ERROR_IO_PENDING : begin
845 handles[0] := overlapped.WaitHandle;
846 handles[1] := FStopServer.Handle;
847 dwWait := WaitForMultipleObjects( 2, @handles, FALSE, FTimeout);
848 FConnected := (dwWait = WAIT_OBJECT_0)
849 and GetOverlappedResult( Handle, overlapped.Overlapped, dwDummy, TRUE)
850 and not QueryStopServer;
851 end;
852
853 else
854 InternalClose;
855 raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
856 'Client connection failed');
857 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000858 end;
Jens Geyere9651362014-03-20 22:46:17 +0200859
860 // create the transport impl
861 result := CreateTransportInstance;
Roger Meier79655fb2012-10-20 20:59:41 +0000862end;
863
864
Jens Geyer06045cf2013-03-27 20:26:25 +0200865function TNamedPipeServerTransportImpl.CreateTransportInstance : ITransport;
866// create the transport impl
867var hPipe : THandle;
Roger Meier79655fb2012-10-20 20:59:41 +0000868begin
Jens Geyer06045cf2013-03-27 20:26:25 +0200869 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
870 try
871 FConnected := FALSE;
Jens Geyere9651362014-03-20 22:46:17 +0200872 result := TNamedPipeTransportServerEndImpl.Create( hPipe, TRUE, FTimeout);
Jens Geyer06045cf2013-03-27 20:26:25 +0200873 except
Jens Geyer01640402013-09-25 21:12:21 +0200874 ClosePipeHandle(hPipe);
875 raise;
876 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000877end;
878
879
Jens Geyer06045cf2013-03-27 20:26:25 +0200880procedure TNamedPipeServerTransportImpl.InternalClose;
881var hPipe : THandle;
882begin
883 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
884 if hPipe = INVALID_HANDLE_VALUE then Exit;
885
886 try
887 if FConnected
888 then FlushFileBuffers( hPipe)
889 else CancelIo( hPipe);
890 DisconnectNamedPipe( hPipe);
891 finally
892 ClosePipeHandle( hPipe);
893 FConnected := FALSE;
894 end;
895end;
896
897
898function TNamedPipeServerTransportImpl.Handle : THandle;
899begin
900 {$IFDEF WIN64}
901 result := THandle( InterlockedExchangeAdd64( Integer(FHandle), 0));
902 {$ELSE}
903 result := THandle( InterlockedExchangeAdd( Integer(FHandle), 0));
904 {$ENDIF}
905end;
906
907
908function TNamedPipeServerTransportImpl.CreateNamedPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000909var SIDAuthWorld : SID_IDENTIFIER_AUTHORITY ;
910 everyone_sid : PSID;
911 ea : EXPLICIT_ACCESS;
912 acl : PACL;
913 sd : PSECURITY_DESCRIPTOR;
914 sa : SECURITY_ATTRIBUTES;
Roger Meier3bef8c22012-10-06 06:58:00 +0000915const
916 SECURITY_WORLD_SID_AUTHORITY : TSIDIdentifierAuthority = (Value : (0,0,0,0,0,1));
917 SECURITY_WORLD_RID = $00000000;
918begin
Jens Geyerb64a7742013-01-23 20:58:47 +0100919 sd := nil;
Roger Meier3bef8c22012-10-06 06:58:00 +0000920 everyone_sid := nil;
Jens Geyerb64a7742013-01-23 20:58:47 +0100921 try
Jens Geyer06045cf2013-03-27 20:26:25 +0200922 ASSERT( (FHandle = INVALID_HANDLE_VALUE) and not FConnected);
923
Jens Geyerb64a7742013-01-23 20:58:47 +0100924 // Windows - set security to allow non-elevated apps
925 // to access pipes created by elevated apps.
926 SIDAuthWorld := SECURITY_WORLD_SID_AUTHORITY;
927 AllocateAndInitializeSid( SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000928
Jens Geyerb64a7742013-01-23 20:58:47 +0100929 ZeroMemory( @ea, SizeOf(ea));
930 ea.grfAccessPermissions := GENERIC_ALL; //SPECIFIC_RIGHTS_ALL or STANDARD_RIGHTS_ALL;
931 ea.grfAccessMode := SET_ACCESS;
932 ea.grfInheritance := NO_INHERITANCE;
933 ea.Trustee.TrusteeForm := TRUSTEE_IS_SID;
934 ea.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
935 ea.Trustee.ptstrName := PChar(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000936
Jens Geyerb64a7742013-01-23 20:58:47 +0100937 acl := nil;
938 SetEntriesInAcl( 1, @ea, nil, acl);
Roger Meier3bef8c22012-10-06 06:58:00 +0000939
Jens Geyerb64a7742013-01-23 20:58:47 +0100940 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
941 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
942 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, acl, FALSE));
Roger Meier3bef8c22012-10-06 06:58:00 +0000943
Jens Geyerb64a7742013-01-23 20:58:47 +0100944 sa.nLength := SizeOf(sa);
945 sa.lpSecurityDescriptor := sd;
946 sa.bInheritHandle := FALSE;
Roger Meier3bef8c22012-10-06 06:58:00 +0000947
Jens Geyerb64a7742013-01-23 20:58:47 +0100948 // Create an instance of the named pipe
Jens Geyer06045cf2013-03-27 20:26:25 +0200949 result := Windows.CreateNamedPipe( PChar( FPipeName), // pipe name
950 PIPE_ACCESS_DUPLEX or // read/write access
951 FILE_FLAG_OVERLAPPED, // async mode
Jens Geyere9651362014-03-20 22:46:17 +0200952 PIPE_TYPE_BYTE or // byte type pipe
953 PIPE_READMODE_BYTE, // byte read mode
Jens Geyer06045cf2013-03-27 20:26:25 +0200954 FMaxConns, // max. instances
955 FBufSize, // output buffer size
956 FBufSize, // input buffer size
957 FTimeout, // time-out, see MSDN
958 @sa); // default security attribute
Roger Meier3bef8c22012-10-06 06:58:00 +0000959
Jens Geyer06045cf2013-03-27 20:26:25 +0200960 if( result <> INVALID_HANDLE_VALUE)
961 then InterlockedExchangePointer( Pointer(FHandle), Pointer(result))
962 else raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
Jens Geyerb64a7742013-01-23 20:58:47 +0100963 'CreateNamedPipe() failed ' + IntToStr(GetLastError));
964
965 finally
966 if sd <> nil then LocalFree( Cardinal( sd));
967 if acl <> nil then LocalFree( Cardinal( acl));
968 if everyone_sid <> nil then FreeSid(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000969 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000970end;
971
972
Roger Meier3bef8c22012-10-06 06:58:00 +0000973
974end.
975
976
977