blob: fc82bf137e32b615ce65ffed870dc12c0686d1c5 [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}
Jens Geyer9f7f11e2016-04-14 21:37:11 +020022{$I Thrift.Defines.inc}
Roger Meier3bef8c22012-10-06 06:58:00 +000023
24interface
25
26uses
Jens Geyer9f7f11e2016-04-14 21:37:11 +020027 {$IFDEF OLD_UNIT_NAMES}
Jens Geyer06045cf2013-03-27 20:26:25 +020028 Windows, SysUtils, Math, AccCtrl, AclAPI, SyncObjs,
Jens Geyer9f7f11e2016-04-14 21:37:11 +020029 {$ELSE}
Nick4f5229e2016-04-14 16:43:22 +030030 Winapi.Windows, System.SysUtils, System.Math, Winapi.AccCtrl, Winapi.AclAPI, System.SyncObjs,
Jens Geyer9f7f11e2016-04-14 21:37:11 +020031 {$ENDIF}
Roger Meier3bef8c22012-10-06 06:58:00 +000032 Thrift.Transport,
Jens Geyere9651362014-03-20 22:46:17 +020033 Thrift.Utils,
Roger Meier3bef8c22012-10-06 06:58:00 +000034 Thrift.Stream;
35
36const
Jens Geyer653f0de2016-04-20 12:46:57 +020037 DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT = 10; // default: fail fast on open
Roger Meier3bef8c22012-10-06 06:58:00 +000038
Jens Geyere9651362014-03-20 22:46:17 +020039
Roger Meier3bef8c22012-10-06 06:58:00 +000040type
Roger Meier79655fb2012-10-20 20:59:41 +000041 //--- Pipe Streams ---
Roger Meier3bef8c22012-10-06 06:58:00 +000042
43
Jens Geyer06045cf2013-03-27 20:26:25 +020044 TPipeStreamBase = class( TThriftStreamImpl)
Roger Meier79655fb2012-10-20 20:59:41 +000045 strict protected
46 FPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +000047 FTimeout : DWORD;
Jens Geyer653f0de2016-04-20 12:46:57 +020048 FOpenTimeOut : DWORD; // separate value to allow for fail-fast-on-open scenarios
Jens Geyere9651362014-03-20 22:46:17 +020049 FOverlapped : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +000050
Roger Meier3bef8c22012-10-06 06:58:00 +000051 procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;
52 function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;
Roger Meier79655fb2012-10-20 20:59:41 +000053 //procedure Open; override; - see derived classes
Roger Meier3bef8c22012-10-06 06:58:00 +000054 procedure Close; override;
55 procedure Flush; override;
56
Jens Geyere9651362014-03-20 22:46:17 +020057 function ReadDirect( var buffer: TBytes; offset: Integer; count: Integer): Integer;
58 function ReadOverlapped( var buffer: TBytes; offset: Integer; count: Integer): Integer;
59 procedure WriteDirect( const buffer: TBytes; offset: Integer; count: Integer);
60 procedure WriteOverlapped( const buffer: TBytes; offset: Integer; count: Integer);
61
Roger Meier3bef8c22012-10-06 06:58:00 +000062 function IsOpen: Boolean; override;
63 function ToArray: TBytes; override;
64 public
Jens Geyer653f0de2016-04-20 12:46:57 +020065 constructor Create( aEnableOverlapped : Boolean;
66 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
67 const aOpenTimeOut : DWORD = DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT);
Roger Meier3bef8c22012-10-06 06:58:00 +000068 destructor Destroy; override;
69 end;
70
71
Jens Geyer06045cf2013-03-27 20:26:25 +020072 TNamedPipeStreamImpl = class sealed( TPipeStreamBase)
Jens Geyere9651362014-03-20 22:46:17 +020073 strict private
Roger Meier79655fb2012-10-20 20:59:41 +000074 FPipeName : string;
75 FShareMode : DWORD;
76 FSecurityAttribs : PSecurityAttributes;
Roger Meier3bef8c22012-10-06 06:58:00 +000077
Jens Geyere9651362014-03-20 22:46:17 +020078 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +000079 procedure Open; override;
80
81 public
82 constructor Create( const aPipeName : string;
Jens Geyere9651362014-03-20 22:46:17 +020083 const aEnableOverlapped : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +000084 const aShareMode: DWORD = 0;
85 const aSecurityAttributes: PSecurityAttributes = nil;
Jens Geyer653f0de2016-04-20 12:46:57 +020086 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
87 const aOpenTimeOut : DWORD = DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT); overload;
Roger Meier79655fb2012-10-20 20:59:41 +000088 end;
89
90
Jens Geyer06045cf2013-03-27 20:26:25 +020091 THandlePipeStreamImpl = class sealed( TPipeStreamBase)
Jens Geyere9651362014-03-20 22:46:17 +020092 strict private
Roger Meier79655fb2012-10-20 20:59:41 +000093 FSrcHandle : THandle;
94
Jens Geyere9651362014-03-20 22:46:17 +020095 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +000096 procedure Open; override;
97
98 public
Jens Geyere9651362014-03-20 22:46:17 +020099 constructor Create( const aPipeHandle : THandle;
100 const aOwnsHandle, aEnableOverlapped : Boolean;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200101 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); overload;
Roger Meier79655fb2012-10-20 20:59:41 +0000102 destructor Destroy; override;
103 end;
104
105
106 //--- Pipe Transports ---
107
108
Jens Geyer06045cf2013-03-27 20:26:25 +0200109 IPipeTransport = interface( IStreamTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000110 ['{5E05CC85-434F-428F-BFB2-856A168B5558}']
111 end;
112
113
Jens Geyer06045cf2013-03-27 20:26:25 +0200114 TPipeTransportBase = class( TStreamTransportImpl, IPipeTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000115 public
116 // ITransport
117 function GetIsOpen: Boolean; override;
118 procedure Open; override;
119 procedure Close; override;
120 end;
121
122
Jens Geyer06045cf2013-03-27 20:26:25 +0200123 TNamedPipeTransportClientEndImpl = class( TPipeTransportBase)
Roger Meier79655fb2012-10-20 20:59:41 +0000124 public
Roger Meier3bef8c22012-10-06 06:58:00 +0000125 // Named pipe constructors
Jens Geyere9651362014-03-20 22:46:17 +0200126 constructor Create( aPipe : THandle; aOwnsHandle : Boolean;
127 const aTimeOut : DWORD); overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000128 constructor Create( const aPipeName : string;
129 const aShareMode: DWORD = 0;
130 const aSecurityAttributes: PSecurityAttributes = nil;
Jens Geyer653f0de2016-04-20 12:46:57 +0200131 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
132 const aOpenTimeOut : DWORD = DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT); overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000133 end;
134
135
Jens Geyer06045cf2013-03-27 20:26:25 +0200136 TNamedPipeTransportServerEndImpl = class( TNamedPipeTransportClientEndImpl)
Roger Meier79655fb2012-10-20 20:59:41 +0000137 strict private
138 FHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000139 public
Roger Meier79655fb2012-10-20 20:59:41 +0000140 // ITransport
141 procedure Close; override;
Jens Geyere9651362014-03-20 22:46:17 +0200142 constructor Create( aPipe : THandle; aOwnsHandle : Boolean;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200143 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); reintroduce;
Roger Meier79655fb2012-10-20 20:59:41 +0000144 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000145
Roger Meier79655fb2012-10-20 20:59:41 +0000146
Jens Geyer06045cf2013-03-27 20:26:25 +0200147 TAnonymousPipeTransportImpl = class( TPipeTransportBase)
Roger Meier79655fb2012-10-20 20:59:41 +0000148 public
Roger Meier3bef8c22012-10-06 06:58:00 +0000149 // Anonymous pipe constructor
Jens Geyerdd074e72016-04-19 23:31:33 +0200150 constructor Create(const aPipeRead, aPipeWrite : THandle;
151 aOwnsHandles : Boolean;
152 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT); overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000153 end;
154
155
Roger Meier79655fb2012-10-20 20:59:41 +0000156 //--- Server Transports ---
157
158
Jens Geyer06045cf2013-03-27 20:26:25 +0200159 IAnonymousPipeServerTransport = interface( IServerTransport)
Roger Meier3bef8c22012-10-06 06:58:00 +0000160 ['{7AEE6793-47B9-4E49-981A-C39E9108E9AD}']
161 // Server side anonymous pipe ends
Roger Meier79655fb2012-10-20 20:59:41 +0000162 function ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000163 function WriteHandle : THandle;
164 // Client side anonymous pipe ends
165 function ClientAnonRead : THandle;
166 function ClientAnonWrite : THandle;
167 end;
168
169
Jens Geyer06045cf2013-03-27 20:26:25 +0200170 INamedPipeServerTransport = interface( IServerTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000171 ['{9DF9EE48-D065-40AF-8F67-D33037D3D960}']
172 function Handle : THandle;
173 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000174
Roger Meier79655fb2012-10-20 20:59:41 +0000175
Jens Geyer06045cf2013-03-27 20:26:25 +0200176 TPipeServerTransportBase = class( TServerTransportImpl)
Jens Geyere9651362014-03-20 22:46:17 +0200177 strict protected
178 FStopServer : TEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200179 procedure InternalClose; virtual; abstract;
Jens Geyere9651362014-03-20 22:46:17 +0200180 function QueryStopServer : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000181 public
Jens Geyere9651362014-03-20 22:46:17 +0200182 constructor Create;
183 destructor Destroy; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000184 procedure Listen; override;
Jens Geyer06045cf2013-03-27 20:26:25 +0200185 procedure Close; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000186 end;
187
188
Jens Geyer06045cf2013-03-27 20:26:25 +0200189 TAnonymousPipeServerTransportImpl = class( TPipeServerTransportBase, IAnonymousPipeServerTransport)
Jens Geyere9651362014-03-20 22:46:17 +0200190 strict private
Roger Meier79655fb2012-10-20 20:59:41 +0000191 FBufSize : DWORD;
192
193 // Server side anonymous pipe handles
194 FReadHandle,
Roger Meier3bef8c22012-10-06 06:58:00 +0000195 FWriteHandle : THandle;
196
197 //Client side anonymous pipe handles
198 FClientAnonRead,
199 FClientAnonWrite : THandle;
200
Jens Geyerdd074e72016-04-19 23:31:33 +0200201 FTimeOut: DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000202 protected
Jens Geyer01640402013-09-25 21:12:21 +0200203 function Accept(const fnAccepting: TProc): ITransport; override;
Roger Meier3bef8c22012-10-06 06:58:00 +0000204
Roger Meier3bef8c22012-10-06 06:58:00 +0000205 function CreateAnonPipe : Boolean;
206
Jens Geyer06045cf2013-03-27 20:26:25 +0200207 // IAnonymousPipeServerTransport
Roger Meier79655fb2012-10-20 20:59:41 +0000208 function ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000209 function WriteHandle : THandle;
210 function ClientAnonRead : THandle;
211 function ClientAnonWrite : THandle;
212
Jens Geyer06045cf2013-03-27 20:26:25 +0200213 procedure InternalClose; override;
214
Roger Meier3bef8c22012-10-06 06:58:00 +0000215 public
Jens Geyerdd074e72016-04-19 23:31:33 +0200216 constructor Create(aBufsize : Cardinal = 4096; aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT);
Roger Meier3bef8c22012-10-06 06:58:00 +0000217 end;
218
219
Jens Geyer06045cf2013-03-27 20:26:25 +0200220 TNamedPipeServerTransportImpl = class( TPipeServerTransportBase, INamedPipeServerTransport)
Jens Geyere9651362014-03-20 22:46:17 +0200221 strict private
Roger Meier79655fb2012-10-20 20:59:41 +0000222 FPipeName : string;
223 FMaxConns : DWORD;
224 FBufSize : DWORD;
Jens Geyer0b20cc82013-03-07 20:47:01 +0100225 FTimeout : DWORD;
Jens Geyer06045cf2013-03-27 20:26:25 +0200226 FHandle : THandle;
227 FConnected : Boolean;
Jens Geyer01640402013-09-25 21:12:21 +0200228
229
Jens Geyere9651362014-03-20 22:46:17 +0200230 strict protected
Jens Geyer01640402013-09-25 21:12:21 +0200231 function Accept(const fnAccepting: TProc): ITransport; override;
Jens Geyer06045cf2013-03-27 20:26:25 +0200232 function CreateNamedPipe : THandle;
233 function CreateTransportInstance : ITransport;
Roger Meier79655fb2012-10-20 20:59:41 +0000234
Jens Geyer06045cf2013-03-27 20:26:25 +0200235 // INamedPipeServerTransport
Roger Meier79655fb2012-10-20 20:59:41 +0000236 function Handle : THandle;
Jens Geyer06045cf2013-03-27 20:26:25 +0200237 procedure InternalClose; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000238
239 public
240 constructor Create( aPipename : string; aBufsize : Cardinal = 4096;
Jens Geyer0b20cc82013-03-07 20:47:01 +0100241 aMaxConns : Cardinal = PIPE_UNLIMITED_INSTANCES;
Jens Geyer2ad6c302015-02-26 19:38:53 +0100242 aTimeOut : Cardinal = INFINITE);
Roger Meier79655fb2012-10-20 20:59:41 +0000243 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000244
245
246implementation
247
248
Roger Meier79655fb2012-10-20 20:59:41 +0000249procedure ClosePipeHandle( var hPipe : THandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000250begin
Roger Meier79655fb2012-10-20 20:59:41 +0000251 if hPipe <> INVALID_HANDLE_VALUE
252 then try
253 CloseHandle( hPipe);
254 finally
255 hPipe := INVALID_HANDLE_VALUE;
256 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000257end;
258
259
Roger Meier79655fb2012-10-20 20:59:41 +0000260function DuplicatePipeHandle( const hSource : THandle) : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000261begin
Roger Meier79655fb2012-10-20 20:59:41 +0000262 if not DuplicateHandle( GetCurrentProcess, hSource,
263 GetCurrentProcess, @result,
264 0, FALSE, DUPLICATE_SAME_ACCESS)
265 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
266 'DuplicateHandle: '+SysErrorMessage(GetLastError));
Roger Meier3bef8c22012-10-06 06:58:00 +0000267end;
268
269
Roger Meier79655fb2012-10-20 20:59:41 +0000270
Jens Geyer06045cf2013-03-27 20:26:25 +0200271{ TPipeStreamBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000272
273
Jens Geyere9651362014-03-20 22:46:17 +0200274constructor TPipeStreamBase.Create( aEnableOverlapped : Boolean;
Jens Geyer653f0de2016-04-20 12:46:57 +0200275 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000276begin
277 inherited Create;
Jens Geyer653f0de2016-04-20 12:46:57 +0200278 ASSERT( aTimeout > 0); // aOpenTimeout may be 0
279 FPipe := INVALID_HANDLE_VALUE;
280 FTimeout := aTimeOut;
281 FOpenTimeOut := aOpenTimeOut;
282 FOverlapped := aEnableOverlapped;
Roger Meier79655fb2012-10-20 20:59:41 +0000283end;
284
285
Jens Geyer06045cf2013-03-27 20:26:25 +0200286destructor TPipeStreamBase.Destroy;
Roger Meier3bef8c22012-10-06 06:58:00 +0000287begin
288 try
289 Close;
290 finally
291 inherited Destroy;
292 end;
293end;
294
295
Jens Geyer06045cf2013-03-27 20:26:25 +0200296procedure TPipeStreamBase.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000297begin
Roger Meier79655fb2012-10-20 20:59:41 +0000298 ClosePipeHandle( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000299end;
300
301
Jens Geyer06045cf2013-03-27 20:26:25 +0200302procedure TPipeStreamBase.Flush;
Roger Meier3bef8c22012-10-06 06:58:00 +0000303begin
Jens Geyer0d227b12015-12-02 19:50:55 +0100304 FlushFileBuffers( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000305end;
306
307
Jens Geyer06045cf2013-03-27 20:26:25 +0200308function TPipeStreamBase.IsOpen: Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000309begin
310 result := (FPipe <> INVALID_HANDLE_VALUE);
311end;
312
313
Jens Geyer06045cf2013-03-27 20:26:25 +0200314procedure TPipeStreamBase.Write(const buffer: TBytes; offset, count: Integer);
Jens Geyere9651362014-03-20 22:46:17 +0200315begin
316 if FOverlapped
317 then WriteOverlapped( buffer, offset, count)
318 else WriteDirect( buffer, offset, count);
319end;
320
321
322function TPipeStreamBase.Read( var buffer: TBytes; offset, count: Integer): Integer;
323begin
324 if FOverlapped
325 then result := ReadOverlapped( buffer, offset, count)
326 else result := ReadDirect( buffer, offset, count);
327end;
328
329
330procedure TPipeStreamBase.WriteDirect(const buffer: TBytes; offset, count: Integer);
Roger Meier3bef8c22012-10-06 06:58:00 +0000331var cbWritten : DWORD;
332begin
333 if not IsOpen
334 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
335 'Called write on non-open pipe');
336
337 if not WriteFile( FPipe, buffer[offset], count, cbWritten, nil)
338 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
339 'Write to pipe failed');
340end;
341
342
Jens Geyere9651362014-03-20 22:46:17 +0200343function TPipeStreamBase.ReadDirect( var buffer: TBytes; offset, count: Integer): Integer;
Roger Meier79655fb2012-10-20 20:59:41 +0000344var cbRead, dwErr : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000345 bytes, retries : LongInt;
346 bOk : Boolean;
347const INTERVAL = 10; // ms
348begin
349 if not IsOpen
350 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
351 'Called read on non-open pipe');
352
353 // MSDN: Handle can be a handle to a named pipe instance,
354 // or it can be a handle to the read end of an anonymous pipe,
355 // The handle must have GENERIC_READ access to the pipe.
356 if FTimeOut <> INFINITE then begin
357 retries := Max( 1, Round( 1.0 * FTimeOut / INTERVAL));
358 while TRUE do begin
Jens Geyer5988f482016-04-19 23:01:24 +0200359 if not PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil) then begin
360 dwErr := GetLastError;
361 if (dwErr = ERROR_INVALID_HANDLE)
362 or (dwErr = ERROR_BROKEN_PIPE)
363 or (dwErr = ERROR_PIPE_NOT_CONNECTED)
364 then begin
365 result := 0; // other side closed the pipe
366 Exit;
367 end;
368 end
369 else if bytes > 0 then begin
370 Break; // there are data
Roger Meier79655fb2012-10-20 20:59:41 +0000371 end;
372
Roger Meier3bef8c22012-10-06 06:58:00 +0000373 Dec( retries);
374 if retries > 0
375 then Sleep( INTERVAL)
376 else raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
377 'Pipe read timed out');
378 end;
379 end;
380
381 // read the data (or block INFINITE-ly)
382 bOk := ReadFile( FPipe, buffer[offset], count, cbRead, nil);
383 if (not bOk) and (GetLastError() <> ERROR_MORE_DATA)
384 then result := 0 // No more data, possibly because client disconnected.
385 else result := cbRead;
386end;
387
388
Jens Geyere9651362014-03-20 22:46:17 +0200389procedure TPipeStreamBase.WriteOverlapped(const buffer: TBytes; offset, count: Integer);
390var cbWritten, dwWait, dwError : DWORD;
391 overlapped : IOverlappedHelper;
392begin
393 if not IsOpen
394 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
395 'Called write on non-open pipe');
396
397 overlapped := TOverlappedHelperImpl.Create;
398
399 if not WriteFile( FPipe, buffer[offset], count, cbWritten, overlapped.OverlappedPtr)
400 then begin
401 dwError := GetLastError;
402 case dwError of
403 ERROR_IO_PENDING : begin
404 dwWait := overlapped.WaitFor(FTimeout);
405
406 if (dwWait = WAIT_TIMEOUT)
407 then raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
408 'Pipe write timed out');
409
410 if (dwWait <> WAIT_OBJECT_0)
411 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbWritten, TRUE)
412 then raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
413 'Pipe write error');
414 end;
415
416 else
417 raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
418 SysErrorMessage(dwError));
419 end;
420 end;
421
422 ASSERT( DWORD(count) = cbWritten);
423end;
424
425
426function TPipeStreamBase.ReadOverlapped( var buffer: TBytes; offset, count: Integer): Integer;
427var cbRead, dwWait, dwError : DWORD;
428 bOk : Boolean;
429 overlapped : IOverlappedHelper;
430begin
431 if not IsOpen
432 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
433 'Called read on non-open pipe');
434
435 overlapped := TOverlappedHelperImpl.Create;
436
437 // read the data
438 bOk := ReadFile( FPipe, buffer[offset], count, cbRead, overlapped.OverlappedPtr);
439 if not bOk then begin
440 dwError := GetLastError;
441 case dwError of
442 ERROR_IO_PENDING : begin
443 dwWait := overlapped.WaitFor(FTimeout);
444
445 if (dwWait = WAIT_TIMEOUT)
446 then raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
447 'Pipe read timed out');
448
449 if (dwWait <> WAIT_OBJECT_0)
450 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbRead, TRUE)
451 then raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
452 'Pipe read error');
453 end;
454
455 else
456 raise TTransportException.Create( TTransportException.TExceptionType.Unknown,
457 SysErrorMessage(dwError));
458 end;
459 end;
460
461 ASSERT( cbRead > 0); // see TTransportImpl.ReadAll()
462 ASSERT( cbRead = DWORD(count));
463 result := cbRead;
464end;
465
466
Jens Geyer06045cf2013-03-27 20:26:25 +0200467function TPipeStreamBase.ToArray: TBytes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000468var bytes : LongInt;
469begin
470 SetLength( result, 0);
471 bytes := 0;
472
473 if IsOpen
474 and PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil)
475 and (bytes > 0)
476 then begin
477 SetLength( result, bytes);
478 Read( result, 0, bytes);
479 end;
480end;
481
482
Roger Meier79655fb2012-10-20 20:59:41 +0000483{ TNamedPipeStreamImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000484
485
Jens Geyere9651362014-03-20 22:46:17 +0200486constructor TNamedPipeStreamImpl.Create( const aPipeName : string;
487 const aEnableOverlapped : Boolean;
488 const aShareMode: DWORD;
Roger Meier79655fb2012-10-20 20:59:41 +0000489 const aSecurityAttributes: PSecurityAttributes;
Jens Geyer653f0de2016-04-20 12:46:57 +0200490 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000491begin
Jens Geyer653f0de2016-04-20 12:46:57 +0200492 inherited Create( aEnableOverlapped, aTimeout, aOpenTimeOut);
Roger Meier79655fb2012-10-20 20:59:41 +0000493
494 FPipeName := aPipeName;
495 FShareMode := aShareMode;
496 FSecurityAttribs := aSecurityAttributes;
497
498 if Copy(FPipeName,1,2) <> '\\'
499 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
Roger Meier3bef8c22012-10-06 06:58:00 +0000500end;
501
502
Roger Meier79655fb2012-10-20 20:59:41 +0000503procedure TNamedPipeStreamImpl.Open;
504var hPipe : THandle;
Jens Geyerb89b5b92016-04-19 23:09:41 +0200505 retries, timeout, dwErr : DWORD;
506const INTERVAL = 10; // ms
Roger Meier79655fb2012-10-20 20:59:41 +0000507begin
508 if IsOpen then Exit;
509
Jens Geyer653f0de2016-04-20 12:46:57 +0200510 retries := Max( 1, Round( 1.0 * FOpenTimeOut / INTERVAL));
511 timeout := FOpenTimeOut;
Jens Geyerb89b5b92016-04-19 23:09:41 +0200512
513 // if the server hasn't gotten to the point where the pipe has been created, at least wait the timeout
514 // According to MSDN, if no instances of the specified named pipe exist, the WaitNamedPipe function
515 // returns IMMEDIATELY, regardless of the time-out value.
Jens Geyer653f0de2016-04-20 12:46:57 +0200516 // Always use INTERVAL, since WaitNamedPipe(0) defaults to some other value
Jens Geyerb89b5b92016-04-19 23:09:41 +0200517 while not WaitNamedPipe( PChar(FPipeName), INTERVAL) do begin
518 dwErr := GetLastError;
519 if dwErr <> ERROR_FILE_NOT_FOUND
520 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
521 'Unable to open pipe, '+SysErrorMessage(dwErr));
522
523 if timeout <> INFINITE then begin
524 if (retries > 0)
525 then Dec(retries)
526 else raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
527 'Unable to open pipe, timed out');
528 end;
529
530 Sleep(INTERVAL)
531 end;
532
Roger Meier79655fb2012-10-20 20:59:41 +0000533 // open that thingy
Roger Meier79655fb2012-10-20 20:59:41 +0000534 hPipe := CreateFile( PChar( FPipeName),
535 GENERIC_READ or GENERIC_WRITE,
536 FShareMode, // sharing
537 FSecurityAttribs, // security attributes
538 OPEN_EXISTING, // opens existing pipe
Jens Geyere9651362014-03-20 22:46:17 +0200539 FILE_FLAG_OVERLAPPED or FILE_FLAG_WRITE_THROUGH, // async+fast, please
Roger Meier79655fb2012-10-20 20:59:41 +0000540 0); // no template file
541
542 if hPipe = INVALID_HANDLE_VALUE
543 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
544 'Unable to open pipe, '+SysErrorMessage(GetLastError));
545
Roger Meier79655fb2012-10-20 20:59:41 +0000546 // everything fine
547 FPipe := hPipe;
548end;
549
550
551{ THandlePipeStreamImpl }
552
553
Jens Geyere9651362014-03-20 22:46:17 +0200554constructor THandlePipeStreamImpl.Create( const aPipeHandle : THandle;
555 const aOwnsHandle, aEnableOverlapped : Boolean;
556 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000557begin
Jens Geyere9651362014-03-20 22:46:17 +0200558 inherited Create( aEnableOverlapped, aTimeOut);
Roger Meier79655fb2012-10-20 20:59:41 +0000559
560 if aOwnsHandle
561 then FSrcHandle := aPipeHandle
562 else FSrcHandle := DuplicatePipeHandle( aPipeHandle);
563
564 Open;
565end;
566
567
568destructor THandlePipeStreamImpl.Destroy;
569begin
570 try
571 ClosePipeHandle( FSrcHandle);
572 finally
573 inherited Destroy;
574 end;
575end;
576
577
578procedure THandlePipeStreamImpl.Open;
579begin
580 if not IsOpen
581 then FPipe := DuplicatePipeHandle( FSrcHandle);
582end;
583
584
Jens Geyer06045cf2013-03-27 20:26:25 +0200585{ TPipeTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000586
587
Jens Geyer06045cf2013-03-27 20:26:25 +0200588function TPipeTransportBase.GetIsOpen: Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000589begin
Jens Geyer0b20cc82013-03-07 20:47:01 +0100590 result := (FInputStream <> nil) and (FInputStream.IsOpen)
591 and (FOutputStream <> nil) and (FOutputStream.IsOpen);
Roger Meier79655fb2012-10-20 20:59:41 +0000592end;
593
594
Jens Geyer06045cf2013-03-27 20:26:25 +0200595procedure TPipeTransportBase.Open;
Roger Meier79655fb2012-10-20 20:59:41 +0000596begin
597 FInputStream.Open;
598 FOutputStream.Open;
599end;
600
601
Jens Geyer06045cf2013-03-27 20:26:25 +0200602procedure TPipeTransportBase.Close;
Roger Meier79655fb2012-10-20 20:59:41 +0000603begin
604 FInputStream.Close;
605 FOutputStream.Close;
606end;
607
608
Jens Geyer06045cf2013-03-27 20:26:25 +0200609{ TNamedPipeTransportClientEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000610
611
Jens Geyer06045cf2013-03-27 20:26:25 +0200612constructor TNamedPipeTransportClientEndImpl.Create( const aPipeName : string; const aShareMode: DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000613 const aSecurityAttributes: PSecurityAttributes;
Jens Geyer653f0de2016-04-20 12:46:57 +0200614 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000615// Named pipe constructor
616begin
Roger Meier79655fb2012-10-20 20:59:41 +0000617 inherited Create( nil, nil);
Jens Geyer653f0de2016-04-20 12:46:57 +0200618 FInputStream := TNamedPipeStreamImpl.Create( aPipeName, TRUE, aShareMode, aSecurityAttributes, aTimeOut, aOpenTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000619 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000620end;
621
622
Jens Geyere9651362014-03-20 22:46:17 +0200623constructor TNamedPipeTransportClientEndImpl.Create( aPipe : THandle; aOwnsHandle : Boolean;
624 const aTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000625// Named pipe constructor
626begin
Roger Meier79655fb2012-10-20 20:59:41 +0000627 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200628 FInputStream := THandlePipeStreamImpl.Create( aPipe, TRUE, aOwnsHandle, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000629 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000630end;
631
632
Jens Geyer06045cf2013-03-27 20:26:25 +0200633{ TNamedPipeTransportServerEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000634
635
Jens Geyere9651362014-03-20 22:46:17 +0200636constructor TNamedPipeTransportServerEndImpl.Create( aPipe : THandle; aOwnsHandle : Boolean;
637 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000638// Named pipe constructor
Roger Meier3bef8c22012-10-06 06:58:00 +0000639begin
Roger Meier79655fb2012-10-20 20:59:41 +0000640 FHandle := DuplicatePipeHandle( aPipe);
Jens Geyere9651362014-03-20 22:46:17 +0200641 inherited Create( aPipe, aOwnsHandle, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000642end;
643
644
Jens Geyer06045cf2013-03-27 20:26:25 +0200645procedure TNamedPipeTransportServerEndImpl.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000646begin
Roger Meier79655fb2012-10-20 20:59:41 +0000647 FlushFileBuffers( FHandle);
648 DisconnectNamedPipe( FHandle); // force client off the pipe
649 ClosePipeHandle( FHandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000650
Roger Meier79655fb2012-10-20 20:59:41 +0000651 inherited Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000652end;
653
654
Jens Geyer06045cf2013-03-27 20:26:25 +0200655{ TAnonymousPipeTransportImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000656
657
Jens Geyerdd074e72016-04-19 23:31:33 +0200658constructor TAnonymousPipeTransportImpl.Create( const aPipeRead, aPipeWrite : THandle;
659 aOwnsHandles : Boolean;
660 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT);
Roger Meier3bef8c22012-10-06 06:58:00 +0000661// Anonymous pipe constructor
662begin
Roger Meier79655fb2012-10-20 20:59:41 +0000663 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200664 // overlapped is not supported with AnonPipes, see MSDN
Jens Geyerdd074e72016-04-19 23:31:33 +0200665 FInputStream := THandlePipeStreamImpl.Create( aPipeRead, aOwnsHandles, FALSE, aTimeOut);
666 FOutputStream := THandlePipeStreamImpl.Create( aPipeWrite, aOwnsHandles, FALSE, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000667end;
668
669
Jens Geyer06045cf2013-03-27 20:26:25 +0200670{ TPipeServerTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000671
672
Jens Geyere9651362014-03-20 22:46:17 +0200673constructor TPipeServerTransportBase.Create;
674begin
675 inherited Create;
676 FStopServer := TEvent.Create(nil,TRUE,FALSE,''); // manual reset
677end;
678
679
680destructor TPipeServerTransportBase.Destroy;
681begin
682 try
683 FreeAndNil( FStopServer);
684 finally
685 inherited Destroy;
686 end;
687end;
688
689
690function TPipeServerTransportBase.QueryStopServer : Boolean;
691begin
692 result := (FStopServer = nil)
693 or (FStopServer.WaitFor(0) <> wrTimeout);
694end;
695
696
Jens Geyer06045cf2013-03-27 20:26:25 +0200697procedure TPipeServerTransportBase.Listen;
Roger Meier3bef8c22012-10-06 06:58:00 +0000698begin
Jens Geyere9651362014-03-20 22:46:17 +0200699 FStopServer.ResetEvent;
Roger Meier3bef8c22012-10-06 06:58:00 +0000700end;
701
702
Jens Geyer06045cf2013-03-27 20:26:25 +0200703procedure TPipeServerTransportBase.Close;
704begin
Jens Geyere9651362014-03-20 22:46:17 +0200705 FStopServer.SetEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200706 InternalClose;
707end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000708
709
Jens Geyer06045cf2013-03-27 20:26:25 +0200710{ TAnonymousPipeServerTransportImpl }
711
712
Jens Geyerdd074e72016-04-19 23:31:33 +0200713constructor TAnonymousPipeServerTransportImpl.Create(aBufsize : Cardinal; aTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000714// Anonymous pipe CTOR
715begin
716 inherited Create;
Roger Meier3bef8c22012-10-06 06:58:00 +0000717 FBufsize := aBufSize;
Roger Meier79655fb2012-10-20 20:59:41 +0000718 FReadHandle := INVALID_HANDLE_VALUE;
Roger Meier3bef8c22012-10-06 06:58:00 +0000719 FWriteHandle := INVALID_HANDLE_VALUE;
720 FClientAnonRead := INVALID_HANDLE_VALUE;
721 FClientAnonWrite := INVALID_HANDLE_VALUE;
Jens Geyerdd074e72016-04-19 23:31:33 +0200722 FTimeOut := aTimeOut;
Roger Meier3bef8c22012-10-06 06:58:00 +0000723
724 // The anonymous pipe needs to be created first so that the server can
725 // pass the handles on to the client before the serve (acceptImpl)
726 // blocking call.
727 if not CreateAnonPipe
728 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
729 ClassName+'.Create() failed');
730end;
731
732
Jens Geyer01640402013-09-25 21:12:21 +0200733function TAnonymousPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Roger Meier3bef8c22012-10-06 06:58:00 +0000734var buf : Byte;
735 br : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000736begin
Jens Geyer01640402013-09-25 21:12:21 +0200737 if Assigned(fnAccepting)
738 then fnAccepting();
739
Roger Meier79655fb2012-10-20 20:59:41 +0000740 // This 0-byte read serves merely as a blocking call.
741 if not ReadFile( FReadHandle, buf, 0, br, nil)
742 and (GetLastError() <> ERROR_MORE_DATA)
743 then raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
744 'TServerPipe unable to initiate pipe communication');
Jens Geyer06045cf2013-03-27 20:26:25 +0200745
746 // create the transport impl
Jens Geyerdd074e72016-04-19 23:31:33 +0200747 result := TAnonymousPipeTransportImpl.Create( FReadHandle, FWriteHandle, FALSE, FTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000748end;
749
750
Jens Geyer06045cf2013-03-27 20:26:25 +0200751procedure TAnonymousPipeServerTransportImpl.InternalClose;
Roger Meier3bef8c22012-10-06 06:58:00 +0000752begin
Roger Meier79655fb2012-10-20 20:59:41 +0000753 ClosePipeHandle( FReadHandle);
754 ClosePipeHandle( FWriteHandle);
755 ClosePipeHandle( FClientAnonRead);
756 ClosePipeHandle( FClientAnonWrite);
Roger Meier3bef8c22012-10-06 06:58:00 +0000757end;
758
759
Jens Geyer06045cf2013-03-27 20:26:25 +0200760function TAnonymousPipeServerTransportImpl.ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000761begin
Roger Meier79655fb2012-10-20 20:59:41 +0000762 result := FReadHandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000763end;
764
765
Jens Geyer06045cf2013-03-27 20:26:25 +0200766function TAnonymousPipeServerTransportImpl.WriteHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000767begin
768 result := FWriteHandle;
769end;
770
771
Jens Geyer06045cf2013-03-27 20:26:25 +0200772function TAnonymousPipeServerTransportImpl.ClientAnonRead : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000773begin
774 result := FClientAnonRead;
775end;
776
777
Jens Geyer06045cf2013-03-27 20:26:25 +0200778function TAnonymousPipeServerTransportImpl.ClientAnonWrite : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000779begin
780 result := FClientAnonWrite;
781end;
782
783
Jens Geyer06045cf2013-03-27 20:26:25 +0200784function TAnonymousPipeServerTransportImpl.CreateAnonPipe : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000785var sd : PSECURITY_DESCRIPTOR;
786 sa : SECURITY_ATTRIBUTES; //TSecurityAttributes;
787 hCAR, hPipeW, hCAW, hPipe : THandle;
788begin
789 result := FALSE;
790
791 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
Jens Geyerb64a7742013-01-23 20:58:47 +0100792 try
793 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
794 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, nil, FALSE));
Roger Meier79655fb2012-10-20 20:59:41 +0000795
Jens Geyerb64a7742013-01-23 20:58:47 +0100796 sa.nLength := sizeof( sa);
797 sa.lpSecurityDescriptor := sd;
798 sa.bInheritHandle := TRUE; //allow passing handle to child
Roger Meier79655fb2012-10-20 20:59:41 +0000799
Jens Geyerb64a7742013-01-23 20:58:47 +0100800 if not CreatePipe( hCAR, hPipeW, @sa, FBufSize) then begin //create stdin pipe
Jens Geyer06045cf2013-03-27 20:26:25 +0200801 raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
802 'TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100803 Exit;
804 end;
805
806 if not CreatePipe( hPipe, hCAW, @sa, FBufSize) then begin //create stdout pipe
Jens Geyerb64a7742013-01-23 20:58:47 +0100807 CloseHandle( hCAR);
808 CloseHandle( hPipeW);
Jens Geyer06045cf2013-03-27 20:26:25 +0200809 raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
810 'TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100811 Exit;
812 end;
813
814 FClientAnonRead := hCAR;
815 FClientAnonWrite := hCAW;
816 FReadHandle := hPipe;
817 FWriteHandle := hPipeW;
818
819 result := TRUE;
Jens Geyerd5436f52014-10-03 19:50:38 +0200820
Jens Geyerb64a7742013-01-23 20:58:47 +0100821 finally
822 if sd <> nil then LocalFree( Cardinal(sd));
Roger Meier79655fb2012-10-20 20:59:41 +0000823 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000824end;
825
826
Jens Geyer06045cf2013-03-27 20:26:25 +0200827{ TNamedPipeServerTransportImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000828
829
Jens Geyer06045cf2013-03-27 20:26:25 +0200830constructor TNamedPipeServerTransportImpl.Create( aPipename : string; aBufsize, aMaxConns, aTimeOut : Cardinal);
Roger Meier79655fb2012-10-20 20:59:41 +0000831// Named Pipe CTOR
832begin
833 inherited Create;
Jens Geyere9651362014-03-20 22:46:17 +0200834 ASSERT( aTimeout > 0);
Jens Geyer06045cf2013-03-27 20:26:25 +0200835 FPipeName := aPipename;
836 FBufsize := aBufSize;
837 FMaxConns := Max( 1, Min( PIPE_UNLIMITED_INSTANCES, aMaxConns));
838 FHandle := INVALID_HANDLE_VALUE;
839 FTimeout := aTimeOut;
840 FConnected := FALSE;
Roger Meier79655fb2012-10-20 20:59:41 +0000841
842 if Copy(FPipeName,1,2) <> '\\'
843 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
844end;
845
846
Jens Geyer01640402013-09-25 21:12:21 +0200847function TNamedPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Jens Geyer06045cf2013-03-27 20:26:25 +0200848var dwError, dwWait, dwDummy : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +0200849 overlapped : IOverlappedHelper;
850 handles : array[0..1] of THandle;
Jens Geyer01640402013-09-25 21:12:21 +0200851begin
Jens Geyere9651362014-03-20 22:46:17 +0200852 overlapped := TOverlappedHelperImpl.Create;
Jens Geyer01640402013-09-25 21:12:21 +0200853
Jens Geyere9651362014-03-20 22:46:17 +0200854 ASSERT( not FConnected);
Jens Geyer2ad6c302015-02-26 19:38:53 +0100855 CreateNamedPipe;
Jens Geyere9651362014-03-20 22:46:17 +0200856 while not FConnected do begin
Jens Geyer2ad6c302015-02-26 19:38:53 +0100857
858 if QueryStopServer
859 then Abort;
Roger Meier79655fb2012-10-20 20:59:41 +0000860
Jens Geyere9651362014-03-20 22:46:17 +0200861 if Assigned(fnAccepting)
862 then fnAccepting();
Jens Geyer01640402013-09-25 21:12:21 +0200863
Jens Geyere9651362014-03-20 22:46:17 +0200864 // Wait for the client to connect; if it succeeds, the
865 // function returns a nonzero value. If the function returns
866 // zero, GetLastError should return ERROR_PIPE_CONNECTED.
867 if ConnectNamedPipe( Handle, overlapped.OverlappedPtr) then begin
868 FConnected := TRUE;
869 Break;
Jens Geyer01640402013-09-25 21:12:21 +0200870 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000871
Jens Geyere9651362014-03-20 22:46:17 +0200872 // ConnectNamedPipe() returns FALSE for OverlappedIO, even if connected.
873 // We have to check GetLastError() explicitly to find out
874 dwError := GetLastError;
875 case dwError of
876 ERROR_PIPE_CONNECTED : begin
877 FConnected := not QueryStopServer; // special case: pipe immediately connected
878 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000879
Jens Geyere9651362014-03-20 22:46:17 +0200880 ERROR_IO_PENDING : begin
881 handles[0] := overlapped.WaitHandle;
882 handles[1] := FStopServer.Handle;
883 dwWait := WaitForMultipleObjects( 2, @handles, FALSE, FTimeout);
884 FConnected := (dwWait = WAIT_OBJECT_0)
885 and GetOverlappedResult( Handle, overlapped.Overlapped, dwDummy, TRUE)
886 and not QueryStopServer;
887 end;
888
889 else
890 InternalClose;
891 raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
892 'Client connection failed');
893 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000894 end;
Jens Geyere9651362014-03-20 22:46:17 +0200895
896 // create the transport impl
897 result := CreateTransportInstance;
Roger Meier79655fb2012-10-20 20:59:41 +0000898end;
899
900
Jens Geyer06045cf2013-03-27 20:26:25 +0200901function TNamedPipeServerTransportImpl.CreateTransportInstance : ITransport;
902// create the transport impl
903var hPipe : THandle;
Roger Meier79655fb2012-10-20 20:59:41 +0000904begin
Jens Geyer06045cf2013-03-27 20:26:25 +0200905 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
906 try
907 FConnected := FALSE;
Jens Geyere9651362014-03-20 22:46:17 +0200908 result := TNamedPipeTransportServerEndImpl.Create( hPipe, TRUE, FTimeout);
Jens Geyer06045cf2013-03-27 20:26:25 +0200909 except
Jens Geyer01640402013-09-25 21:12:21 +0200910 ClosePipeHandle(hPipe);
911 raise;
912 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000913end;
914
915
Jens Geyer06045cf2013-03-27 20:26:25 +0200916procedure TNamedPipeServerTransportImpl.InternalClose;
917var hPipe : THandle;
918begin
919 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
920 if hPipe = INVALID_HANDLE_VALUE then Exit;
921
922 try
923 if FConnected
924 then FlushFileBuffers( hPipe)
925 else CancelIo( hPipe);
926 DisconnectNamedPipe( hPipe);
927 finally
928 ClosePipeHandle( hPipe);
929 FConnected := FALSE;
930 end;
931end;
932
933
934function TNamedPipeServerTransportImpl.Handle : THandle;
935begin
936 {$IFDEF WIN64}
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200937 result := THandle( InterlockedExchangeAdd64( Int64(FHandle), 0));
Jens Geyer06045cf2013-03-27 20:26:25 +0200938 {$ELSE}
939 result := THandle( InterlockedExchangeAdd( Integer(FHandle), 0));
940 {$ENDIF}
941end;
942
943
944function TNamedPipeServerTransportImpl.CreateNamedPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000945var SIDAuthWorld : SID_IDENTIFIER_AUTHORITY ;
946 everyone_sid : PSID;
947 ea : EXPLICIT_ACCESS;
948 acl : PACL;
949 sd : PSECURITY_DESCRIPTOR;
950 sa : SECURITY_ATTRIBUTES;
Roger Meier3bef8c22012-10-06 06:58:00 +0000951const
952 SECURITY_WORLD_SID_AUTHORITY : TSIDIdentifierAuthority = (Value : (0,0,0,0,0,1));
953 SECURITY_WORLD_RID = $00000000;
954begin
Jens Geyerb64a7742013-01-23 20:58:47 +0100955 sd := nil;
Roger Meier3bef8c22012-10-06 06:58:00 +0000956 everyone_sid := nil;
Jens Geyerb64a7742013-01-23 20:58:47 +0100957 try
Jens Geyer06045cf2013-03-27 20:26:25 +0200958 ASSERT( (FHandle = INVALID_HANDLE_VALUE) and not FConnected);
959
Jens Geyerb64a7742013-01-23 20:58:47 +0100960 // Windows - set security to allow non-elevated apps
961 // to access pipes created by elevated apps.
962 SIDAuthWorld := SECURITY_WORLD_SID_AUTHORITY;
963 AllocateAndInitializeSid( SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000964
Jens Geyerb64a7742013-01-23 20:58:47 +0100965 ZeroMemory( @ea, SizeOf(ea));
966 ea.grfAccessPermissions := GENERIC_ALL; //SPECIFIC_RIGHTS_ALL or STANDARD_RIGHTS_ALL;
967 ea.grfAccessMode := SET_ACCESS;
968 ea.grfInheritance := NO_INHERITANCE;
969 ea.Trustee.TrusteeForm := TRUSTEE_IS_SID;
970 ea.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
971 ea.Trustee.ptstrName := PChar(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000972
Jens Geyerb64a7742013-01-23 20:58:47 +0100973 acl := nil;
974 SetEntriesInAcl( 1, @ea, nil, acl);
Roger Meier3bef8c22012-10-06 06:58:00 +0000975
Jens Geyerb64a7742013-01-23 20:58:47 +0100976 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
977 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
978 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, acl, FALSE));
Roger Meier3bef8c22012-10-06 06:58:00 +0000979
Jens Geyerb64a7742013-01-23 20:58:47 +0100980 sa.nLength := SizeOf(sa);
981 sa.lpSecurityDescriptor := sd;
982 sa.bInheritHandle := FALSE;
Roger Meier3bef8c22012-10-06 06:58:00 +0000983
Jens Geyerb64a7742013-01-23 20:58:47 +0100984 // Create an instance of the named pipe
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200985 {$IFDEF OLD_UNIT_NAMES}
986 result := Windows.CreateNamedPipe(
987 {$ELSE}
988 result := Winapi.Windows.CreateNamedPipe(
989 {$ENDIF}
990 PChar( FPipeName), // pipe name
991 PIPE_ACCESS_DUPLEX or // read/write access
992 FILE_FLAG_OVERLAPPED, // async mode
993 PIPE_TYPE_BYTE or // byte type pipe
994 PIPE_READMODE_BYTE, // byte read mode
995 FMaxConns, // max. instances
996 FBufSize, // output buffer size
997 FBufSize, // input buffer size
998 FTimeout, // time-out, see MSDN
999 @sa // default security attribute
1000 );
Roger Meier3bef8c22012-10-06 06:58:00 +00001001
Jens Geyer06045cf2013-03-27 20:26:25 +02001002 if( result <> INVALID_HANDLE_VALUE)
1003 then InterlockedExchangePointer( Pointer(FHandle), Pointer(result))
1004 else raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
Jens Geyerb64a7742013-01-23 20:58:47 +01001005 'CreateNamedPipe() failed ' + IntToStr(GetLastError));
1006
1007 finally
1008 if sd <> nil then LocalFree( Cardinal( sd));
1009 if acl <> nil then LocalFree( Cardinal( acl));
1010 if everyone_sid <> nil then FreeSid(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +00001011 end;
Roger Meier3bef8c22012-10-06 06:58:00 +00001012end;
1013
1014
Roger Meier3bef8c22012-10-06 06:58:00 +00001015
1016end.
1017
1018
1019