blob: fe96d724c205c7cd79a97446cfb25eaaae07e0b7 [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
Jens Geyer17c3ad92017-09-05 20:31:27 +020051 procedure Write( const pBuf : Pointer; offset, count : Integer); override;
52 function Read( const pBuf : Pointer; const buflen : Integer; 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 Geyer17c3ad92017-09-05 20:31:27 +020057 function ReadDirect( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload;
58 function ReadOverlapped( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload;
59 procedure WriteDirect( const pBuf : Pointer; offset: Integer; count: Integer); overload;
60 procedure WriteOverlapped( const pBuf : Pointer; offset: Integer; count: Integer); overload;
Jens Geyere9651362014-03-20 22:46:17 +020061
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)
Jens Geyere0e32402016-04-20 21:50:48 +0200265 then raise TTransportExceptionNotOpen.Create('DuplicateHandle: '+SysErrorMessage(GetLastError));
Roger Meier3bef8c22012-10-06 06:58:00 +0000266end;
267
268
Roger Meier79655fb2012-10-20 20:59:41 +0000269
Jens Geyer06045cf2013-03-27 20:26:25 +0200270{ TPipeStreamBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000271
272
Jens Geyere9651362014-03-20 22:46:17 +0200273constructor TPipeStreamBase.Create( aEnableOverlapped : Boolean;
Jens Geyer653f0de2016-04-20 12:46:57 +0200274 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000275begin
276 inherited Create;
Jens Geyer653f0de2016-04-20 12:46:57 +0200277 ASSERT( aTimeout > 0); // aOpenTimeout may be 0
278 FPipe := INVALID_HANDLE_VALUE;
279 FTimeout := aTimeOut;
280 FOpenTimeOut := aOpenTimeOut;
281 FOverlapped := aEnableOverlapped;
Roger Meier79655fb2012-10-20 20:59:41 +0000282end;
283
284
Jens Geyer06045cf2013-03-27 20:26:25 +0200285destructor TPipeStreamBase.Destroy;
Roger Meier3bef8c22012-10-06 06:58:00 +0000286begin
287 try
288 Close;
289 finally
290 inherited Destroy;
291 end;
292end;
293
294
Jens Geyer06045cf2013-03-27 20:26:25 +0200295procedure TPipeStreamBase.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000296begin
Roger Meier79655fb2012-10-20 20:59:41 +0000297 ClosePipeHandle( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000298end;
299
300
Jens Geyer06045cf2013-03-27 20:26:25 +0200301procedure TPipeStreamBase.Flush;
Roger Meier3bef8c22012-10-06 06:58:00 +0000302begin
Jens Geyer0d227b12015-12-02 19:50:55 +0100303 FlushFileBuffers( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000304end;
305
306
Jens Geyer06045cf2013-03-27 20:26:25 +0200307function TPipeStreamBase.IsOpen: Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000308begin
309 result := (FPipe <> INVALID_HANDLE_VALUE);
310end;
311
312
Jens Geyer17c3ad92017-09-05 20:31:27 +0200313procedure TPipeStreamBase.Write( const pBuf : Pointer; offset, count : Integer);
Jens Geyere9651362014-03-20 22:46:17 +0200314begin
315 if FOverlapped
Jens Geyer17c3ad92017-09-05 20:31:27 +0200316 then WriteOverlapped( pBuf, offset, count)
317 else WriteDirect( pBuf, offset, count);
Jens Geyere9651362014-03-20 22:46:17 +0200318end;
319
320
Jens Geyer17c3ad92017-09-05 20:31:27 +0200321function TPipeStreamBase.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyere9651362014-03-20 22:46:17 +0200322begin
323 if FOverlapped
Jens Geyer17c3ad92017-09-05 20:31:27 +0200324 then result := ReadOverlapped( pBuf, buflen, offset, count)
325 else result := ReadDirect( pBuf, buflen, offset, count);
Jens Geyere9651362014-03-20 22:46:17 +0200326end;
327
328
Jens Geyer17c3ad92017-09-05 20:31:27 +0200329procedure TPipeStreamBase.WriteDirect( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyerd4df9172017-10-25 22:30:23 +0200330var cbWritten, nBytes : DWORD;
Jens Geyer85827152018-01-12 21:20:59 +0100331 pData : PByte;
Roger Meier3bef8c22012-10-06 06:58:00 +0000332begin
333 if not IsOpen
Jens Geyere0e32402016-04-20 21:50:48 +0200334 then raise TTransportExceptionNotOpen.Create('Called write on non-open pipe');
Roger Meier3bef8c22012-10-06 06:58:00 +0000335
Jens Geyerd4df9172017-10-25 22:30:23 +0200336 // if necessary, send the data in chunks
337 // there's a system limit around 0x10000 bytes that we hit otherwise
338 // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
339 nBytes := Min( 15*4096, count); // 16 would exceed the limit
Jens Geyer85827152018-01-12 21:20:59 +0100340 pData := pBuf;
341 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200342 while nBytes > 0 do begin
Jens Geyer85827152018-01-12 21:20:59 +0100343 if not WriteFile( FPipe, pData^, nBytes, cbWritten, nil)
Jens Geyerd4df9172017-10-25 22:30:23 +0200344 then raise TTransportExceptionNotOpen.Create('Write to pipe failed');
345
Jens Geyer85827152018-01-12 21:20:59 +0100346 Inc( pData, cbWritten);
Jens Geyerd4df9172017-10-25 22:30:23 +0200347 Dec( count, cbWritten);
348 nBytes := Min( nBytes, count);
349 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000350end;
351
352
Jens Geyer17c3ad92017-09-05 20:31:27 +0200353procedure TPipeStreamBase.WriteOverlapped( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyerd4df9172017-10-25 22:30:23 +0200354var cbWritten, dwWait, dwError, nBytes : DWORD;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200355 overlapped : IOverlappedHelper;
Jens Geyer85827152018-01-12 21:20:59 +0100356 pData : PByte;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200357begin
358 if not IsOpen
359 then raise TTransportExceptionNotOpen.Create('Called write on non-open pipe');
360
Jens Geyerd4df9172017-10-25 22:30:23 +0200361 // if necessary, send the data in chunks
362 // there's a system limit around 0x10000 bytes that we hit otherwise
363 // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
364 nBytes := Min( 15*4096, count); // 16 would exceed the limit
Jens Geyer85827152018-01-12 21:20:59 +0100365 pData := pBuf;
366 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200367 while nBytes > 0 do begin
368 overlapped := TOverlappedHelperImpl.Create;
Jens Geyer85827152018-01-12 21:20:59 +0100369 if not WriteFile( FPipe, pData^, nBytes, cbWritten, overlapped.OverlappedPtr)
Jens Geyerd4df9172017-10-25 22:30:23 +0200370 then begin
371 dwError := GetLastError;
372 case dwError of
373 ERROR_IO_PENDING : begin
374 dwWait := overlapped.WaitFor(FTimeout);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200375
Jens Geyerd4df9172017-10-25 22:30:23 +0200376 if (dwWait = WAIT_TIMEOUT)
377 then raise TTransportExceptionTimedOut.Create('Pipe write timed out');
Jens Geyer17c3ad92017-09-05 20:31:27 +0200378
Jens Geyerd4df9172017-10-25 22:30:23 +0200379 if (dwWait <> WAIT_OBJECT_0)
380 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbWritten, TRUE)
381 then raise TTransportExceptionUnknown.Create('Pipe write error');
382 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200383
Jens Geyerd4df9172017-10-25 22:30:23 +0200384 else
385 raise TTransportExceptionUnknown.Create(SysErrorMessage(dwError));
Jens Geyer17c3ad92017-09-05 20:31:27 +0200386 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200387 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200388
Jens Geyerd4df9172017-10-25 22:30:23 +0200389 ASSERT( DWORD(nBytes) = cbWritten);
390
Jens Geyer85827152018-01-12 21:20:59 +0100391 Inc( pData, cbWritten);
Jens Geyerd4df9172017-10-25 22:30:23 +0200392 Dec( count, cbWritten);
393 nBytes := Min( nBytes, count);
394 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200395end;
396
397
398function TPipeStreamBase.ReadDirect( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd4df9172017-10-25 22:30:23 +0200399var cbRead, dwErr, nRemaining : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000400 bytes, retries : LongInt;
401 bOk : Boolean;
Jens Geyer85827152018-01-12 21:20:59 +0100402 pData : PByte;
Roger Meier3bef8c22012-10-06 06:58:00 +0000403const INTERVAL = 10; // ms
404begin
405 if not IsOpen
Jens Geyere0e32402016-04-20 21:50:48 +0200406 then raise TTransportExceptionNotOpen.Create('Called read on non-open pipe');
Roger Meier3bef8c22012-10-06 06:58:00 +0000407
408 // MSDN: Handle can be a handle to a named pipe instance,
409 // or it can be a handle to the read end of an anonymous pipe,
410 // The handle must have GENERIC_READ access to the pipe.
411 if FTimeOut <> INFINITE then begin
412 retries := Max( 1, Round( 1.0 * FTimeOut / INTERVAL));
413 while TRUE do begin
Jens Geyer5988f482016-04-19 23:01:24 +0200414 if not PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil) then begin
415 dwErr := GetLastError;
416 if (dwErr = ERROR_INVALID_HANDLE)
417 or (dwErr = ERROR_BROKEN_PIPE)
418 or (dwErr = ERROR_PIPE_NOT_CONNECTED)
419 then begin
420 result := 0; // other side closed the pipe
421 Exit;
422 end;
423 end
424 else if bytes > 0 then begin
425 Break; // there are data
Roger Meier79655fb2012-10-20 20:59:41 +0000426 end;
427
Roger Meier3bef8c22012-10-06 06:58:00 +0000428 Dec( retries);
429 if retries > 0
430 then Sleep( INTERVAL)
Jens Geyere0e32402016-04-20 21:50:48 +0200431 else raise TTransportExceptionTimedOut.Create('Pipe read timed out');
Roger Meier3bef8c22012-10-06 06:58:00 +0000432 end;
433 end;
434
Jens Geyerd4df9172017-10-25 22:30:23 +0200435 result := 0;
436 nRemaining := count;
Jens Geyer85827152018-01-12 21:20:59 +0100437 pData := pBuf;
438 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200439 while nRemaining > 0 do begin
440 // read the data (or block INFINITE-ly)
Jens Geyer85827152018-01-12 21:20:59 +0100441 bOk := ReadFile( FPipe, pData^, nRemaining, cbRead, nil);
Jens Geyerd4df9172017-10-25 22:30:23 +0200442 if (not bOk) and (GetLastError() <> ERROR_MORE_DATA)
443 then Break; // No more data, possibly because client disconnected.
444
445 Dec( nRemaining, cbRead);
Jens Geyer85827152018-01-12 21:20:59 +0100446 Inc( pData, cbRead);
Jens Geyerd4df9172017-10-25 22:30:23 +0200447 Inc( result, cbRead);
448 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000449end;
450
451
Jens Geyer17c3ad92017-09-05 20:31:27 +0200452function TPipeStreamBase.ReadOverlapped( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd4df9172017-10-25 22:30:23 +0200453var cbRead, dwWait, dwError, nRemaining : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +0200454 bOk : Boolean;
455 overlapped : IOverlappedHelper;
Jens Geyer85827152018-01-12 21:20:59 +0100456 pData : PByte;
Jens Geyere9651362014-03-20 22:46:17 +0200457begin
458 if not IsOpen
Jens Geyere0e32402016-04-20 21:50:48 +0200459 then raise TTransportExceptionNotOpen.Create('Called read on non-open pipe');
Jens Geyere9651362014-03-20 22:46:17 +0200460
Jens Geyerd4df9172017-10-25 22:30:23 +0200461 result := 0;
462 nRemaining := count;
Jens Geyer85827152018-01-12 21:20:59 +0100463 pData := pBuf;
464 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200465 while nRemaining > 0 do begin
466 overlapped := TOverlappedHelperImpl.Create;
Jens Geyere9651362014-03-20 22:46:17 +0200467
Jens Geyerd4df9172017-10-25 22:30:23 +0200468 // read the data
Jens Geyer85827152018-01-12 21:20:59 +0100469 bOk := ReadFile( FPipe, pData^, nRemaining, cbRead, overlapped.OverlappedPtr);
Jens Geyerd4df9172017-10-25 22:30:23 +0200470 if not bOk then begin
471 dwError := GetLastError;
472 case dwError of
473 ERROR_IO_PENDING : begin
474 dwWait := overlapped.WaitFor(FTimeout);
Jens Geyere9651362014-03-20 22:46:17 +0200475
Jens Geyerd4df9172017-10-25 22:30:23 +0200476 if (dwWait = WAIT_TIMEOUT)
477 then raise TTransportExceptionTimedOut.Create('Pipe read timed out');
Jens Geyere9651362014-03-20 22:46:17 +0200478
Jens Geyerd4df9172017-10-25 22:30:23 +0200479 if (dwWait <> WAIT_OBJECT_0)
480 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbRead, TRUE)
481 then raise TTransportExceptionUnknown.Create('Pipe read error');
482 end;
483
484 else
485 raise TTransportExceptionUnknown.Create(SysErrorMessage(dwError));
Jens Geyere9651362014-03-20 22:46:17 +0200486 end;
Jens Geyere9651362014-03-20 22:46:17 +0200487 end;
Jens Geyere9651362014-03-20 22:46:17 +0200488
Jens Geyerd4df9172017-10-25 22:30:23 +0200489 ASSERT( cbRead > 0); // see TTransportImpl.ReadAll()
490 ASSERT( cbRead <= DWORD(nRemaining));
491 Dec( nRemaining, cbRead);
Jens Geyer85827152018-01-12 21:20:59 +0100492 Inc( pData, cbRead);
Jens Geyerd4df9172017-10-25 22:30:23 +0200493 Inc( result, cbRead);
494 end;
Jens Geyere9651362014-03-20 22:46:17 +0200495end;
496
497
Jens Geyer06045cf2013-03-27 20:26:25 +0200498function TPipeStreamBase.ToArray: TBytes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000499var bytes : LongInt;
500begin
501 SetLength( result, 0);
502 bytes := 0;
503
504 if IsOpen
505 and PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil)
506 and (bytes > 0)
507 then begin
508 SetLength( result, bytes);
509 Read( result, 0, bytes);
510 end;
511end;
512
513
Roger Meier79655fb2012-10-20 20:59:41 +0000514{ TNamedPipeStreamImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000515
516
Jens Geyere9651362014-03-20 22:46:17 +0200517constructor TNamedPipeStreamImpl.Create( const aPipeName : string;
518 const aEnableOverlapped : Boolean;
519 const aShareMode: DWORD;
Roger Meier79655fb2012-10-20 20:59:41 +0000520 const aSecurityAttributes: PSecurityAttributes;
Jens Geyer653f0de2016-04-20 12:46:57 +0200521 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000522begin
Jens Geyer653f0de2016-04-20 12:46:57 +0200523 inherited Create( aEnableOverlapped, aTimeout, aOpenTimeOut);
Roger Meier79655fb2012-10-20 20:59:41 +0000524
525 FPipeName := aPipeName;
526 FShareMode := aShareMode;
527 FSecurityAttribs := aSecurityAttributes;
528
529 if Copy(FPipeName,1,2) <> '\\'
530 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
Roger Meier3bef8c22012-10-06 06:58:00 +0000531end;
532
533
Roger Meier79655fb2012-10-20 20:59:41 +0000534procedure TNamedPipeStreamImpl.Open;
535var hPipe : THandle;
Jens Geyerb89b5b92016-04-19 23:09:41 +0200536 retries, timeout, dwErr : DWORD;
537const INTERVAL = 10; // ms
Roger Meier79655fb2012-10-20 20:59:41 +0000538begin
539 if IsOpen then Exit;
540
Jens Geyer653f0de2016-04-20 12:46:57 +0200541 retries := Max( 1, Round( 1.0 * FOpenTimeOut / INTERVAL));
542 timeout := FOpenTimeOut;
Jens Geyerb89b5b92016-04-19 23:09:41 +0200543
544 // if the server hasn't gotten to the point where the pipe has been created, at least wait the timeout
545 // According to MSDN, if no instances of the specified named pipe exist, the WaitNamedPipe function
546 // returns IMMEDIATELY, regardless of the time-out value.
Jens Geyer653f0de2016-04-20 12:46:57 +0200547 // Always use INTERVAL, since WaitNamedPipe(0) defaults to some other value
Jens Geyerb89b5b92016-04-19 23:09:41 +0200548 while not WaitNamedPipe( PChar(FPipeName), INTERVAL) do begin
549 dwErr := GetLastError;
550 if dwErr <> ERROR_FILE_NOT_FOUND
Jens Geyere0e32402016-04-20 21:50:48 +0200551 then raise TTransportExceptionNotOpen.Create('Unable to open pipe, '+SysErrorMessage(dwErr));
Jens Geyerb89b5b92016-04-19 23:09:41 +0200552
553 if timeout <> INFINITE then begin
554 if (retries > 0)
555 then Dec(retries)
Jens Geyere0e32402016-04-20 21:50:48 +0200556 else raise TTransportExceptionNotOpen.Create('Unable to open pipe, timed out');
Jens Geyerb89b5b92016-04-19 23:09:41 +0200557 end;
558
559 Sleep(INTERVAL)
560 end;
561
Roger Meier79655fb2012-10-20 20:59:41 +0000562 // open that thingy
Roger Meier79655fb2012-10-20 20:59:41 +0000563 hPipe := CreateFile( PChar( FPipeName),
564 GENERIC_READ or GENERIC_WRITE,
565 FShareMode, // sharing
566 FSecurityAttribs, // security attributes
567 OPEN_EXISTING, // opens existing pipe
Jens Geyere9651362014-03-20 22:46:17 +0200568 FILE_FLAG_OVERLAPPED or FILE_FLAG_WRITE_THROUGH, // async+fast, please
Roger Meier79655fb2012-10-20 20:59:41 +0000569 0); // no template file
570
571 if hPipe = INVALID_HANDLE_VALUE
Jens Geyere0e32402016-04-20 21:50:48 +0200572 then raise TTransportExceptionNotOpen.Create('Unable to open pipe, '+SysErrorMessage(GetLastError));
Roger Meier79655fb2012-10-20 20:59:41 +0000573
Roger Meier79655fb2012-10-20 20:59:41 +0000574 // everything fine
575 FPipe := hPipe;
576end;
577
578
579{ THandlePipeStreamImpl }
580
581
Jens Geyere9651362014-03-20 22:46:17 +0200582constructor THandlePipeStreamImpl.Create( const aPipeHandle : THandle;
583 const aOwnsHandle, aEnableOverlapped : Boolean;
584 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000585begin
Jens Geyere9651362014-03-20 22:46:17 +0200586 inherited Create( aEnableOverlapped, aTimeOut);
Roger Meier79655fb2012-10-20 20:59:41 +0000587
588 if aOwnsHandle
589 then FSrcHandle := aPipeHandle
590 else FSrcHandle := DuplicatePipeHandle( aPipeHandle);
591
592 Open;
593end;
594
595
596destructor THandlePipeStreamImpl.Destroy;
597begin
598 try
599 ClosePipeHandle( FSrcHandle);
600 finally
601 inherited Destroy;
602 end;
603end;
604
605
606procedure THandlePipeStreamImpl.Open;
607begin
608 if not IsOpen
609 then FPipe := DuplicatePipeHandle( FSrcHandle);
610end;
611
612
Jens Geyer06045cf2013-03-27 20:26:25 +0200613{ TPipeTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000614
615
Jens Geyer06045cf2013-03-27 20:26:25 +0200616function TPipeTransportBase.GetIsOpen: Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000617begin
Jens Geyer0b20cc82013-03-07 20:47:01 +0100618 result := (FInputStream <> nil) and (FInputStream.IsOpen)
619 and (FOutputStream <> nil) and (FOutputStream.IsOpen);
Roger Meier79655fb2012-10-20 20:59:41 +0000620end;
621
622
Jens Geyer06045cf2013-03-27 20:26:25 +0200623procedure TPipeTransportBase.Open;
Roger Meier79655fb2012-10-20 20:59:41 +0000624begin
625 FInputStream.Open;
626 FOutputStream.Open;
627end;
628
629
Jens Geyer06045cf2013-03-27 20:26:25 +0200630procedure TPipeTransportBase.Close;
Roger Meier79655fb2012-10-20 20:59:41 +0000631begin
632 FInputStream.Close;
633 FOutputStream.Close;
634end;
635
636
Jens Geyer06045cf2013-03-27 20:26:25 +0200637{ TNamedPipeTransportClientEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000638
639
Jens Geyer06045cf2013-03-27 20:26:25 +0200640constructor TNamedPipeTransportClientEndImpl.Create( const aPipeName : string; const aShareMode: DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000641 const aSecurityAttributes: PSecurityAttributes;
Jens Geyer653f0de2016-04-20 12:46:57 +0200642 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000643// Named pipe constructor
644begin
Roger Meier79655fb2012-10-20 20:59:41 +0000645 inherited Create( nil, nil);
Jens Geyer653f0de2016-04-20 12:46:57 +0200646 FInputStream := TNamedPipeStreamImpl.Create( aPipeName, TRUE, aShareMode, aSecurityAttributes, aTimeOut, aOpenTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000647 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000648end;
649
650
Jens Geyere9651362014-03-20 22:46:17 +0200651constructor TNamedPipeTransportClientEndImpl.Create( aPipe : THandle; aOwnsHandle : Boolean;
652 const aTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000653// Named pipe constructor
654begin
Roger Meier79655fb2012-10-20 20:59:41 +0000655 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200656 FInputStream := THandlePipeStreamImpl.Create( aPipe, TRUE, aOwnsHandle, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000657 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000658end;
659
660
Jens Geyer06045cf2013-03-27 20:26:25 +0200661{ TNamedPipeTransportServerEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000662
663
Jens Geyere9651362014-03-20 22:46:17 +0200664constructor TNamedPipeTransportServerEndImpl.Create( aPipe : THandle; aOwnsHandle : Boolean;
665 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000666// Named pipe constructor
Roger Meier3bef8c22012-10-06 06:58:00 +0000667begin
Roger Meier79655fb2012-10-20 20:59:41 +0000668 FHandle := DuplicatePipeHandle( aPipe);
Jens Geyere9651362014-03-20 22:46:17 +0200669 inherited Create( aPipe, aOwnsHandle, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000670end;
671
672
Jens Geyer06045cf2013-03-27 20:26:25 +0200673procedure TNamedPipeTransportServerEndImpl.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000674begin
Roger Meier79655fb2012-10-20 20:59:41 +0000675 FlushFileBuffers( FHandle);
676 DisconnectNamedPipe( FHandle); // force client off the pipe
677 ClosePipeHandle( FHandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000678
Roger Meier79655fb2012-10-20 20:59:41 +0000679 inherited Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000680end;
681
682
Jens Geyer06045cf2013-03-27 20:26:25 +0200683{ TAnonymousPipeTransportImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000684
685
Jens Geyerdd074e72016-04-19 23:31:33 +0200686constructor TAnonymousPipeTransportImpl.Create( const aPipeRead, aPipeWrite : THandle;
687 aOwnsHandles : Boolean;
688 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT);
Roger Meier3bef8c22012-10-06 06:58:00 +0000689// Anonymous pipe constructor
690begin
Roger Meier79655fb2012-10-20 20:59:41 +0000691 inherited Create( nil, nil);
Jens Geyere9651362014-03-20 22:46:17 +0200692 // overlapped is not supported with AnonPipes, see MSDN
Jens Geyerdd074e72016-04-19 23:31:33 +0200693 FInputStream := THandlePipeStreamImpl.Create( aPipeRead, aOwnsHandles, FALSE, aTimeOut);
694 FOutputStream := THandlePipeStreamImpl.Create( aPipeWrite, aOwnsHandles, FALSE, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000695end;
696
697
Jens Geyer06045cf2013-03-27 20:26:25 +0200698{ TPipeServerTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000699
700
Jens Geyere9651362014-03-20 22:46:17 +0200701constructor TPipeServerTransportBase.Create;
702begin
703 inherited Create;
704 FStopServer := TEvent.Create(nil,TRUE,FALSE,''); // manual reset
705end;
706
707
708destructor TPipeServerTransportBase.Destroy;
709begin
710 try
711 FreeAndNil( FStopServer);
712 finally
713 inherited Destroy;
714 end;
715end;
716
717
718function TPipeServerTransportBase.QueryStopServer : Boolean;
719begin
720 result := (FStopServer = nil)
721 or (FStopServer.WaitFor(0) <> wrTimeout);
722end;
723
724
Jens Geyer06045cf2013-03-27 20:26:25 +0200725procedure TPipeServerTransportBase.Listen;
Roger Meier3bef8c22012-10-06 06:58:00 +0000726begin
Jens Geyere9651362014-03-20 22:46:17 +0200727 FStopServer.ResetEvent;
Roger Meier3bef8c22012-10-06 06:58:00 +0000728end;
729
730
Jens Geyer06045cf2013-03-27 20:26:25 +0200731procedure TPipeServerTransportBase.Close;
732begin
Jens Geyere9651362014-03-20 22:46:17 +0200733 FStopServer.SetEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200734 InternalClose;
735end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000736
737
Jens Geyer06045cf2013-03-27 20:26:25 +0200738{ TAnonymousPipeServerTransportImpl }
739
740
Jens Geyerdd074e72016-04-19 23:31:33 +0200741constructor TAnonymousPipeServerTransportImpl.Create(aBufsize : Cardinal; aTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000742// Anonymous pipe CTOR
743begin
744 inherited Create;
Roger Meier3bef8c22012-10-06 06:58:00 +0000745 FBufsize := aBufSize;
Roger Meier79655fb2012-10-20 20:59:41 +0000746 FReadHandle := INVALID_HANDLE_VALUE;
Roger Meier3bef8c22012-10-06 06:58:00 +0000747 FWriteHandle := INVALID_HANDLE_VALUE;
748 FClientAnonRead := INVALID_HANDLE_VALUE;
749 FClientAnonWrite := INVALID_HANDLE_VALUE;
Jens Geyerdd074e72016-04-19 23:31:33 +0200750 FTimeOut := aTimeOut;
Roger Meier3bef8c22012-10-06 06:58:00 +0000751
752 // The anonymous pipe needs to be created first so that the server can
753 // pass the handles on to the client before the serve (acceptImpl)
754 // blocking call.
755 if not CreateAnonPipe
Jens Geyere0e32402016-04-20 21:50:48 +0200756 then raise TTransportExceptionNotOpen.Create(ClassName+'.Create() failed');
Roger Meier3bef8c22012-10-06 06:58:00 +0000757end;
758
759
Jens Geyer01640402013-09-25 21:12:21 +0200760function TAnonymousPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Roger Meier3bef8c22012-10-06 06:58:00 +0000761var buf : Byte;
762 br : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000763begin
Jens Geyer01640402013-09-25 21:12:21 +0200764 if Assigned(fnAccepting)
765 then fnAccepting();
766
Roger Meier79655fb2012-10-20 20:59:41 +0000767 // This 0-byte read serves merely as a blocking call.
768 if not ReadFile( FReadHandle, buf, 0, br, nil)
769 and (GetLastError() <> ERROR_MORE_DATA)
Jens Geyere0e32402016-04-20 21:50:48 +0200770 then raise TTransportExceptionNotOpen.Create('TServerPipe unable to initiate pipe communication');
Jens Geyer06045cf2013-03-27 20:26:25 +0200771
772 // create the transport impl
Jens Geyerdd074e72016-04-19 23:31:33 +0200773 result := TAnonymousPipeTransportImpl.Create( FReadHandle, FWriteHandle, FALSE, FTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000774end;
775
776
Jens Geyer06045cf2013-03-27 20:26:25 +0200777procedure TAnonymousPipeServerTransportImpl.InternalClose;
Roger Meier3bef8c22012-10-06 06:58:00 +0000778begin
Roger Meier79655fb2012-10-20 20:59:41 +0000779 ClosePipeHandle( FReadHandle);
780 ClosePipeHandle( FWriteHandle);
781 ClosePipeHandle( FClientAnonRead);
782 ClosePipeHandle( FClientAnonWrite);
Roger Meier3bef8c22012-10-06 06:58:00 +0000783end;
784
785
Jens Geyer06045cf2013-03-27 20:26:25 +0200786function TAnonymousPipeServerTransportImpl.ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000787begin
Roger Meier79655fb2012-10-20 20:59:41 +0000788 result := FReadHandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000789end;
790
791
Jens Geyer06045cf2013-03-27 20:26:25 +0200792function TAnonymousPipeServerTransportImpl.WriteHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000793begin
794 result := FWriteHandle;
795end;
796
797
Jens Geyer06045cf2013-03-27 20:26:25 +0200798function TAnonymousPipeServerTransportImpl.ClientAnonRead : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000799begin
800 result := FClientAnonRead;
801end;
802
803
Jens Geyer06045cf2013-03-27 20:26:25 +0200804function TAnonymousPipeServerTransportImpl.ClientAnonWrite : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000805begin
806 result := FClientAnonWrite;
807end;
808
809
Jens Geyer06045cf2013-03-27 20:26:25 +0200810function TAnonymousPipeServerTransportImpl.CreateAnonPipe : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000811var sd : PSECURITY_DESCRIPTOR;
812 sa : SECURITY_ATTRIBUTES; //TSecurityAttributes;
813 hCAR, hPipeW, hCAW, hPipe : THandle;
814begin
Roger Meier79655fb2012-10-20 20:59:41 +0000815 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
Jens Geyerb64a7742013-01-23 20:58:47 +0100816 try
817 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
818 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, nil, FALSE));
Roger Meier79655fb2012-10-20 20:59:41 +0000819
Jens Geyerb64a7742013-01-23 20:58:47 +0100820 sa.nLength := sizeof( sa);
821 sa.lpSecurityDescriptor := sd;
822 sa.bInheritHandle := TRUE; //allow passing handle to child
Roger Meier79655fb2012-10-20 20:59:41 +0000823
Jens Geyer17c3ad92017-09-05 20:31:27 +0200824 Result := CreatePipe( hCAR, hPipeW, @sa, FBufSize); //create stdin pipe
825 if not Result then begin //create stdin pipe
Jens Geyere0e32402016-04-20 21:50:48 +0200826 raise TTransportExceptionNotOpen.Create('TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100827 Exit;
828 end;
829
Jens Geyer17c3ad92017-09-05 20:31:27 +0200830 Result := CreatePipe( hPipe, hCAW, @sa, FBufSize); //create stdout pipe
831 if not Result then begin //create stdout pipe
Jens Geyerb64a7742013-01-23 20:58:47 +0100832 CloseHandle( hCAR);
833 CloseHandle( hPipeW);
Jens Geyere0e32402016-04-20 21:50:48 +0200834 raise TTransportExceptionNotOpen.Create('TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100835 Exit;
836 end;
837
838 FClientAnonRead := hCAR;
839 FClientAnonWrite := hCAW;
840 FReadHandle := hPipe;
841 FWriteHandle := hPipeW;
Jens Geyerb64a7742013-01-23 20:58:47 +0100842 finally
843 if sd <> nil then LocalFree( Cardinal(sd));
Roger Meier79655fb2012-10-20 20:59:41 +0000844 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000845end;
846
847
Jens Geyer06045cf2013-03-27 20:26:25 +0200848{ TNamedPipeServerTransportImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000849
850
Jens Geyer06045cf2013-03-27 20:26:25 +0200851constructor TNamedPipeServerTransportImpl.Create( aPipename : string; aBufsize, aMaxConns, aTimeOut : Cardinal);
Roger Meier79655fb2012-10-20 20:59:41 +0000852// Named Pipe CTOR
853begin
854 inherited Create;
Jens Geyere9651362014-03-20 22:46:17 +0200855 ASSERT( aTimeout > 0);
Jens Geyer06045cf2013-03-27 20:26:25 +0200856 FPipeName := aPipename;
857 FBufsize := aBufSize;
858 FMaxConns := Max( 1, Min( PIPE_UNLIMITED_INSTANCES, aMaxConns));
859 FHandle := INVALID_HANDLE_VALUE;
860 FTimeout := aTimeOut;
861 FConnected := FALSE;
Roger Meier79655fb2012-10-20 20:59:41 +0000862
863 if Copy(FPipeName,1,2) <> '\\'
864 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
865end;
866
867
Jens Geyer01640402013-09-25 21:12:21 +0200868function TNamedPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Jens Geyer06045cf2013-03-27 20:26:25 +0200869var dwError, dwWait, dwDummy : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +0200870 overlapped : IOverlappedHelper;
871 handles : array[0..1] of THandle;
Jens Geyer01640402013-09-25 21:12:21 +0200872begin
Jens Geyere9651362014-03-20 22:46:17 +0200873 overlapped := TOverlappedHelperImpl.Create;
Jens Geyer01640402013-09-25 21:12:21 +0200874
Jens Geyere9651362014-03-20 22:46:17 +0200875 ASSERT( not FConnected);
Jens Geyer2ad6c302015-02-26 19:38:53 +0100876 CreateNamedPipe;
Jens Geyere9651362014-03-20 22:46:17 +0200877 while not FConnected do begin
Jens Geyer2ad6c302015-02-26 19:38:53 +0100878
879 if QueryStopServer
880 then Abort;
Roger Meier79655fb2012-10-20 20:59:41 +0000881
Jens Geyere9651362014-03-20 22:46:17 +0200882 if Assigned(fnAccepting)
883 then fnAccepting();
Jens Geyer01640402013-09-25 21:12:21 +0200884
Jens Geyere9651362014-03-20 22:46:17 +0200885 // Wait for the client to connect; if it succeeds, the
886 // function returns a nonzero value. If the function returns
887 // zero, GetLastError should return ERROR_PIPE_CONNECTED.
888 if ConnectNamedPipe( Handle, overlapped.OverlappedPtr) then begin
889 FConnected := TRUE;
890 Break;
Jens Geyer01640402013-09-25 21:12:21 +0200891 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000892
Jens Geyere9651362014-03-20 22:46:17 +0200893 // ConnectNamedPipe() returns FALSE for OverlappedIO, even if connected.
894 // We have to check GetLastError() explicitly to find out
895 dwError := GetLastError;
896 case dwError of
897 ERROR_PIPE_CONNECTED : begin
898 FConnected := not QueryStopServer; // special case: pipe immediately connected
899 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000900
Jens Geyere9651362014-03-20 22:46:17 +0200901 ERROR_IO_PENDING : begin
902 handles[0] := overlapped.WaitHandle;
903 handles[1] := FStopServer.Handle;
904 dwWait := WaitForMultipleObjects( 2, @handles, FALSE, FTimeout);
905 FConnected := (dwWait = WAIT_OBJECT_0)
906 and GetOverlappedResult( Handle, overlapped.Overlapped, dwDummy, TRUE)
907 and not QueryStopServer;
908 end;
909
910 else
911 InternalClose;
Jens Geyere0e32402016-04-20 21:50:48 +0200912 raise TTransportExceptionNotOpen.Create('Client connection failed');
Jens Geyere9651362014-03-20 22:46:17 +0200913 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000914 end;
Jens Geyere9651362014-03-20 22:46:17 +0200915
916 // create the transport impl
917 result := CreateTransportInstance;
Roger Meier79655fb2012-10-20 20:59:41 +0000918end;
919
920
Jens Geyer06045cf2013-03-27 20:26:25 +0200921function TNamedPipeServerTransportImpl.CreateTransportInstance : ITransport;
922// create the transport impl
923var hPipe : THandle;
Roger Meier79655fb2012-10-20 20:59:41 +0000924begin
Jens Geyer06045cf2013-03-27 20:26:25 +0200925 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
926 try
927 FConnected := FALSE;
Jens Geyere9651362014-03-20 22:46:17 +0200928 result := TNamedPipeTransportServerEndImpl.Create( hPipe, TRUE, FTimeout);
Jens Geyer06045cf2013-03-27 20:26:25 +0200929 except
Jens Geyer01640402013-09-25 21:12:21 +0200930 ClosePipeHandle(hPipe);
931 raise;
932 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000933end;
934
935
Jens Geyer06045cf2013-03-27 20:26:25 +0200936procedure TNamedPipeServerTransportImpl.InternalClose;
937var hPipe : THandle;
938begin
939 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
940 if hPipe = INVALID_HANDLE_VALUE then Exit;
941
942 try
943 if FConnected
944 then FlushFileBuffers( hPipe)
945 else CancelIo( hPipe);
946 DisconnectNamedPipe( hPipe);
947 finally
948 ClosePipeHandle( hPipe);
949 FConnected := FALSE;
950 end;
951end;
952
953
954function TNamedPipeServerTransportImpl.Handle : THandle;
955begin
956 {$IFDEF WIN64}
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200957 result := THandle( InterlockedExchangeAdd64( Int64(FHandle), 0));
Jens Geyer06045cf2013-03-27 20:26:25 +0200958 {$ELSE}
959 result := THandle( InterlockedExchangeAdd( Integer(FHandle), 0));
960 {$ENDIF}
961end;
962
963
964function TNamedPipeServerTransportImpl.CreateNamedPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000965var SIDAuthWorld : SID_IDENTIFIER_AUTHORITY ;
966 everyone_sid : PSID;
967 ea : EXPLICIT_ACCESS;
968 acl : PACL;
969 sd : PSECURITY_DESCRIPTOR;
970 sa : SECURITY_ATTRIBUTES;
Roger Meier3bef8c22012-10-06 06:58:00 +0000971const
972 SECURITY_WORLD_SID_AUTHORITY : TSIDIdentifierAuthority = (Value : (0,0,0,0,0,1));
973 SECURITY_WORLD_RID = $00000000;
974begin
Jens Geyerb64a7742013-01-23 20:58:47 +0100975 sd := nil;
Roger Meier3bef8c22012-10-06 06:58:00 +0000976 everyone_sid := nil;
Jens Geyerb64a7742013-01-23 20:58:47 +0100977 try
Jens Geyer06045cf2013-03-27 20:26:25 +0200978 ASSERT( (FHandle = INVALID_HANDLE_VALUE) and not FConnected);
979
Jens Geyerb64a7742013-01-23 20:58:47 +0100980 // Windows - set security to allow non-elevated apps
981 // to access pipes created by elevated apps.
982 SIDAuthWorld := SECURITY_WORLD_SID_AUTHORITY;
983 AllocateAndInitializeSid( SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000984
Jens Geyerb64a7742013-01-23 20:58:47 +0100985 ZeroMemory( @ea, SizeOf(ea));
986 ea.grfAccessPermissions := GENERIC_ALL; //SPECIFIC_RIGHTS_ALL or STANDARD_RIGHTS_ALL;
987 ea.grfAccessMode := SET_ACCESS;
988 ea.grfInheritance := NO_INHERITANCE;
989 ea.Trustee.TrusteeForm := TRUSTEE_IS_SID;
990 ea.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
991 ea.Trustee.ptstrName := PChar(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +0000992
Jens Geyerb64a7742013-01-23 20:58:47 +0100993 acl := nil;
994 SetEntriesInAcl( 1, @ea, nil, acl);
Roger Meier3bef8c22012-10-06 06:58:00 +0000995
Jens Geyerb64a7742013-01-23 20:58:47 +0100996 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
997 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
998 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, acl, FALSE));
Roger Meier3bef8c22012-10-06 06:58:00 +0000999
Jens Geyerb64a7742013-01-23 20:58:47 +01001000 sa.nLength := SizeOf(sa);
1001 sa.lpSecurityDescriptor := sd;
1002 sa.bInheritHandle := FALSE;
Roger Meier3bef8c22012-10-06 06:58:00 +00001003
Jens Geyerb64a7742013-01-23 20:58:47 +01001004 // Create an instance of the named pipe
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001005 {$IFDEF OLD_UNIT_NAMES}
1006 result := Windows.CreateNamedPipe(
1007 {$ELSE}
1008 result := Winapi.Windows.CreateNamedPipe(
1009 {$ENDIF}
1010 PChar( FPipeName), // pipe name
1011 PIPE_ACCESS_DUPLEX or // read/write access
1012 FILE_FLAG_OVERLAPPED, // async mode
1013 PIPE_TYPE_BYTE or // byte type pipe
1014 PIPE_READMODE_BYTE, // byte read mode
1015 FMaxConns, // max. instances
1016 FBufSize, // output buffer size
1017 FBufSize, // input buffer size
1018 FTimeout, // time-out, see MSDN
1019 @sa // default security attribute
1020 );
Roger Meier3bef8c22012-10-06 06:58:00 +00001021
Jens Geyer06045cf2013-03-27 20:26:25 +02001022 if( result <> INVALID_HANDLE_VALUE)
1023 then InterlockedExchangePointer( Pointer(FHandle), Pointer(result))
Jens Geyere0e32402016-04-20 21:50:48 +02001024 else raise TTransportExceptionNotOpen.Create('CreateNamedPipe() failed ' + IntToStr(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +01001025
1026 finally
1027 if sd <> nil then LocalFree( Cardinal( sd));
1028 if acl <> nil then LocalFree( Cardinal( acl));
1029 if everyone_sid <> nil then FreeSid(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +00001030 end;
Roger Meier3bef8c22012-10-06 06:58:00 +00001031end;
1032
1033
Roger Meier3bef8c22012-10-06 06:58:00 +00001034
1035end.
1036
1037
1038