blob: 635a8417859435c768b1152ce8d90d57b503e827 [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}
Jens Geyera019cda2019-11-09 23:24:52 +010032 Thrift.Configuration,
Roger Meier3bef8c22012-10-06 06:58:00 +000033 Thrift.Transport,
Jens Geyere9651362014-03-20 22:46:17 +020034 Thrift.Utils,
Roger Meier3bef8c22012-10-06 06:58:00 +000035 Thrift.Stream;
36
37const
Jens Geyer653f0de2016-04-20 12:46:57 +020038 DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT = 10; // default: fail fast on open
Roger Meier3bef8c22012-10-06 06:58:00 +000039
Jens Geyere9651362014-03-20 22:46:17 +020040
Roger Meier3bef8c22012-10-06 06:58:00 +000041type
Roger Meier79655fb2012-10-20 20:59:41 +000042 //--- Pipe Streams ---
Roger Meier3bef8c22012-10-06 06:58:00 +000043
44
Jens Geyer06045cf2013-03-27 20:26:25 +020045 TPipeStreamBase = class( TThriftStreamImpl)
Roger Meier79655fb2012-10-20 20:59:41 +000046 strict protected
47 FPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +000048 FTimeout : DWORD;
Jens Geyer653f0de2016-04-20 12:46:57 +020049 FOpenTimeOut : DWORD; // separate value to allow for fail-fast-on-open scenarios
Jens Geyere9651362014-03-20 22:46:17 +020050 FOverlapped : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +000051
Jens Geyer17c3ad92017-09-05 20:31:27 +020052 procedure Write( const pBuf : Pointer; offset, count : Integer); override;
53 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Roger Meier79655fb2012-10-20 20:59:41 +000054 //procedure Open; override; - see derived classes
Roger Meier3bef8c22012-10-06 06:58:00 +000055 procedure Close; override;
56 procedure Flush; override;
57
Jens Geyer17c3ad92017-09-05 20:31:27 +020058 function ReadDirect( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload;
59 function ReadOverlapped( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload;
60 procedure WriteDirect( const pBuf : Pointer; offset: Integer; count: Integer); overload;
61 procedure WriteOverlapped( const pBuf : Pointer; offset: Integer; count: Integer); overload;
Jens Geyere9651362014-03-20 22:46:17 +020062
Roger Meier3bef8c22012-10-06 06:58:00 +000063 function IsOpen: Boolean; override;
64 function ToArray: TBytes; override;
65 public
Jens Geyer653f0de2016-04-20 12:46:57 +020066 constructor Create( aEnableOverlapped : Boolean;
67 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
Jens Geyera019cda2019-11-09 23:24:52 +010068 const aOpenTimeOut : DWORD = DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT
69 ); reintroduce; overload;
70
Roger Meier3bef8c22012-10-06 06:58:00 +000071 destructor Destroy; override;
72 end;
73
74
Jens Geyer06045cf2013-03-27 20:26:25 +020075 TNamedPipeStreamImpl = class sealed( TPipeStreamBase)
Jens Geyere9651362014-03-20 22:46:17 +020076 strict private
Roger Meier79655fb2012-10-20 20:59:41 +000077 FPipeName : string;
78 FShareMode : DWORD;
79 FSecurityAttribs : PSecurityAttributes;
Roger Meier3bef8c22012-10-06 06:58:00 +000080
Jens Geyere9651362014-03-20 22:46:17 +020081 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +000082 procedure Open; override;
83
84 public
85 constructor Create( const aPipeName : string;
Jens Geyere9651362014-03-20 22:46:17 +020086 const aEnableOverlapped : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +000087 const aShareMode: DWORD = 0;
88 const aSecurityAttributes: PSecurityAttributes = nil;
Jens Geyer653f0de2016-04-20 12:46:57 +020089 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
Jens Geyera019cda2019-11-09 23:24:52 +010090 const aOpenTimeOut : DWORD = DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT
91 ); reintroduce; overload;
Roger Meier79655fb2012-10-20 20:59:41 +000092 end;
93
94
Jens Geyer06045cf2013-03-27 20:26:25 +020095 THandlePipeStreamImpl = class sealed( TPipeStreamBase)
Jens Geyere9651362014-03-20 22:46:17 +020096 strict private
Roger Meier79655fb2012-10-20 20:59:41 +000097 FSrcHandle : THandle;
98
Jens Geyere9651362014-03-20 22:46:17 +020099 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +0000100 procedure Open; override;
101
102 public
Jens Geyere9651362014-03-20 22:46:17 +0200103 constructor Create( const aPipeHandle : THandle;
104 const aOwnsHandle, aEnableOverlapped : Boolean;
Jens Geyera019cda2019-11-09 23:24:52 +0100105 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT
106 ); reintroduce; overload;
107
Roger Meier79655fb2012-10-20 20:59:41 +0000108 destructor Destroy; override;
109 end;
110
111
112 //--- Pipe Transports ---
113
114
Jens Geyer06045cf2013-03-27 20:26:25 +0200115 IPipeTransport = interface( IStreamTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000116 ['{5E05CC85-434F-428F-BFB2-856A168B5558}']
117 end;
118
119
Jens Geyer06045cf2013-03-27 20:26:25 +0200120 TPipeTransportBase = class( TStreamTransportImpl, IPipeTransport)
Jens Geyera019cda2019-11-09 23:24:52 +0100121 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +0000122 // ITransport
123 function GetIsOpen: Boolean; override;
124 procedure Open; override;
125 procedure Close; override;
126 end;
127
128
Jens Geyer06045cf2013-03-27 20:26:25 +0200129 TNamedPipeTransportClientEndImpl = class( TPipeTransportBase)
Roger Meier79655fb2012-10-20 20:59:41 +0000130 public
Roger Meier3bef8c22012-10-06 06:58:00 +0000131 // Named pipe constructors
Jens Geyer41f47af2019-11-09 23:24:52 +0100132 constructor Create( const aPipe : THandle;
133 const aOwnsHandle : Boolean;
134 const aTimeOut : DWORD;
Jens Geyera019cda2019-11-09 23:24:52 +0100135 const aConfig : IThriftConfiguration = nil
136 ); reintroduce; overload;
Jens Geyer41f47af2019-11-09 23:24:52 +0100137
Roger Meier3bef8c22012-10-06 06:58:00 +0000138 constructor Create( const aPipeName : string;
139 const aShareMode: DWORD = 0;
140 const aSecurityAttributes: PSecurityAttributes = nil;
Jens Geyer653f0de2016-04-20 12:46:57 +0200141 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
Jens Geyer41f47af2019-11-09 23:24:52 +0100142 const aOpenTimeOut : DWORD = DEFAULT_THRIFT_PIPE_OPEN_TIMEOUT;
Jens Geyera019cda2019-11-09 23:24:52 +0100143 const aConfig : IThriftConfiguration = nil
144 ); reintroduce; overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000145 end;
146
147
Jens Geyer06045cf2013-03-27 20:26:25 +0200148 TNamedPipeTransportServerEndImpl = class( TNamedPipeTransportClientEndImpl)
Roger Meier79655fb2012-10-20 20:59:41 +0000149 strict private
150 FHandle : THandle;
Jens Geyera019cda2019-11-09 23:24:52 +0100151 strict protected
Roger Meier79655fb2012-10-20 20:59:41 +0000152 // ITransport
153 procedure Close; override;
Jens Geyera019cda2019-11-09 23:24:52 +0100154 public
Jens Geyer41f47af2019-11-09 23:24:52 +0100155 constructor Create( const aPipe : THandle;
156 const aOwnsHandle : Boolean;
157 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
Jens Geyera019cda2019-11-09 23:24:52 +0100158 const aConfig : IThriftConfiguration = nil
159 ); reintroduce; overload;
160
Roger Meier79655fb2012-10-20 20:59:41 +0000161 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000162
Roger Meier79655fb2012-10-20 20:59:41 +0000163
Jens Geyer06045cf2013-03-27 20:26:25 +0200164 TAnonymousPipeTransportImpl = class( TPipeTransportBase)
Roger Meier79655fb2012-10-20 20:59:41 +0000165 public
Roger Meier3bef8c22012-10-06 06:58:00 +0000166 // Anonymous pipe constructor
Jens Geyer41f47af2019-11-09 23:24:52 +0100167 constructor Create( const aPipeRead, aPipeWrite : THandle;
168 const aOwnsHandles : Boolean;
169 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
Jens Geyera019cda2019-11-09 23:24:52 +0100170 const aConfig : IThriftConfiguration = nil
171 ); reintroduce; overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000172 end;
173
174
Roger Meier79655fb2012-10-20 20:59:41 +0000175 //--- Server Transports ---
176
177
Jens Geyer06045cf2013-03-27 20:26:25 +0200178 IAnonymousPipeServerTransport = interface( IServerTransport)
Roger Meier3bef8c22012-10-06 06:58:00 +0000179 ['{7AEE6793-47B9-4E49-981A-C39E9108E9AD}']
180 // Server side anonymous pipe ends
Roger Meier79655fb2012-10-20 20:59:41 +0000181 function ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000182 function WriteHandle : THandle;
183 // Client side anonymous pipe ends
184 function ClientAnonRead : THandle;
185 function ClientAnonWrite : THandle;
186 end;
187
188
Jens Geyer06045cf2013-03-27 20:26:25 +0200189 INamedPipeServerTransport = interface( IServerTransport)
Roger Meier79655fb2012-10-20 20:59:41 +0000190 ['{9DF9EE48-D065-40AF-8F67-D33037D3D960}']
191 function Handle : THandle;
192 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000193
Roger Meier79655fb2012-10-20 20:59:41 +0000194
Jens Geyer06045cf2013-03-27 20:26:25 +0200195 TPipeServerTransportBase = class( TServerTransportImpl)
Jens Geyere9651362014-03-20 22:46:17 +0200196 strict protected
197 FStopServer : TEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200198 procedure InternalClose; virtual; abstract;
Jens Geyere9651362014-03-20 22:46:17 +0200199 function QueryStopServer : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000200 public
Jens Geyera019cda2019-11-09 23:24:52 +0100201 constructor Create( const aConfig : IThriftConfiguration);
Jens Geyere9651362014-03-20 22:46:17 +0200202 destructor Destroy; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000203 procedure Listen; override;
Jens Geyer06045cf2013-03-27 20:26:25 +0200204 procedure Close; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000205 end;
206
207
Jens Geyer06045cf2013-03-27 20:26:25 +0200208 TAnonymousPipeServerTransportImpl = class( TPipeServerTransportBase, IAnonymousPipeServerTransport)
Jens Geyere9651362014-03-20 22:46:17 +0200209 strict private
Roger Meier79655fb2012-10-20 20:59:41 +0000210 FBufSize : DWORD;
211
212 // Server side anonymous pipe handles
213 FReadHandle,
Roger Meier3bef8c22012-10-06 06:58:00 +0000214 FWriteHandle : THandle;
215
216 //Client side anonymous pipe handles
217 FClientAnonRead,
218 FClientAnonWrite : THandle;
219
Jens Geyerdd074e72016-04-19 23:31:33 +0200220 FTimeOut: DWORD;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100221 strict protected
Jens Geyer01640402013-09-25 21:12:21 +0200222 function Accept(const fnAccepting: TProc): ITransport; override;
Roger Meier3bef8c22012-10-06 06:58:00 +0000223
Roger Meier3bef8c22012-10-06 06:58:00 +0000224 function CreateAnonPipe : Boolean;
225
Jens Geyer06045cf2013-03-27 20:26:25 +0200226 // IAnonymousPipeServerTransport
Roger Meier79655fb2012-10-20 20:59:41 +0000227 function ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000228 function WriteHandle : THandle;
229 function ClientAnonRead : THandle;
230 function ClientAnonWrite : THandle;
231
Jens Geyer06045cf2013-03-27 20:26:25 +0200232 procedure InternalClose; override;
233
Roger Meier3bef8c22012-10-06 06:58:00 +0000234 public
Jens Geyera019cda2019-11-09 23:24:52 +0100235 constructor Create( const aBufsize : Cardinal = 4096;
236 const aTimeOut : DWORD = DEFAULT_THRIFT_TIMEOUT;
237 const aConfig : IThriftConfiguration = nil
238 ); reintroduce; overload;
Roger Meier3bef8c22012-10-06 06:58:00 +0000239 end;
240
241
Jens Geyer06045cf2013-03-27 20:26:25 +0200242 TNamedPipeServerTransportImpl = class( TPipeServerTransportBase, INamedPipeServerTransport)
Jens Geyere9651362014-03-20 22:46:17 +0200243 strict private
Roger Meier79655fb2012-10-20 20:59:41 +0000244 FPipeName : string;
245 FMaxConns : DWORD;
246 FBufSize : DWORD;
Jens Geyer0b20cc82013-03-07 20:47:01 +0100247 FTimeout : DWORD;
Jens Geyer06045cf2013-03-27 20:26:25 +0200248 FHandle : THandle;
249 FConnected : Boolean;
Jens Geyer01640402013-09-25 21:12:21 +0200250
251
Jens Geyere9651362014-03-20 22:46:17 +0200252 strict protected
Jens Geyer01640402013-09-25 21:12:21 +0200253 function Accept(const fnAccepting: TProc): ITransport; override;
Jens Geyer06045cf2013-03-27 20:26:25 +0200254 function CreateNamedPipe : THandle;
255 function CreateTransportInstance : ITransport;
Roger Meier79655fb2012-10-20 20:59:41 +0000256
Jens Geyer06045cf2013-03-27 20:26:25 +0200257 // INamedPipeServerTransport
Roger Meier79655fb2012-10-20 20:59:41 +0000258 function Handle : THandle;
Jens Geyer06045cf2013-03-27 20:26:25 +0200259 procedure InternalClose; override;
Roger Meier79655fb2012-10-20 20:59:41 +0000260
261 public
Jens Geyera019cda2019-11-09 23:24:52 +0100262 constructor Create( const aPipename : string;
263 const aBufsize : Cardinal = 4096;
264 const aMaxConns : Cardinal = PIPE_UNLIMITED_INSTANCES;
265 const aTimeOut : Cardinal = INFINITE;
266 const aConfig : IThriftConfiguration = nil
267 ); reintroduce; overload;
Roger Meier79655fb2012-10-20 20:59:41 +0000268 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000269
270
271implementation
272
273
Roger Meier79655fb2012-10-20 20:59:41 +0000274procedure ClosePipeHandle( var hPipe : THandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000275begin
Roger Meier79655fb2012-10-20 20:59:41 +0000276 if hPipe <> INVALID_HANDLE_VALUE
277 then try
278 CloseHandle( hPipe);
279 finally
280 hPipe := INVALID_HANDLE_VALUE;
281 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000282end;
283
284
Roger Meier79655fb2012-10-20 20:59:41 +0000285function DuplicatePipeHandle( const hSource : THandle) : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000286begin
Roger Meier79655fb2012-10-20 20:59:41 +0000287 if not DuplicateHandle( GetCurrentProcess, hSource,
288 GetCurrentProcess, @result,
289 0, FALSE, DUPLICATE_SAME_ACCESS)
Jens Geyere0e32402016-04-20 21:50:48 +0200290 then raise TTransportExceptionNotOpen.Create('DuplicateHandle: '+SysErrorMessage(GetLastError));
Roger Meier3bef8c22012-10-06 06:58:00 +0000291end;
292
293
Roger Meier79655fb2012-10-20 20:59:41 +0000294
Jens Geyer06045cf2013-03-27 20:26:25 +0200295{ TPipeStreamBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000296
297
Jens Geyera019cda2019-11-09 23:24:52 +0100298constructor TPipeStreamBase.Create( aEnableOverlapped : Boolean; const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000299begin
300 inherited Create;
Jens Geyer653f0de2016-04-20 12:46:57 +0200301 FPipe := INVALID_HANDLE_VALUE;
302 FTimeout := aTimeOut;
303 FOpenTimeOut := aOpenTimeOut;
304 FOverlapped := aEnableOverlapped;
Jens Geyera019cda2019-11-09 23:24:52 +0100305 ASSERT( FTimeout > 0); // FOpenTimeout may be 0
Roger Meier79655fb2012-10-20 20:59:41 +0000306end;
307
308
Jens Geyer06045cf2013-03-27 20:26:25 +0200309destructor TPipeStreamBase.Destroy;
Roger Meier3bef8c22012-10-06 06:58:00 +0000310begin
311 try
312 Close;
313 finally
314 inherited Destroy;
315 end;
316end;
317
318
Jens Geyer06045cf2013-03-27 20:26:25 +0200319procedure TPipeStreamBase.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000320begin
Roger Meier79655fb2012-10-20 20:59:41 +0000321 ClosePipeHandle( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000322end;
323
324
Jens Geyer06045cf2013-03-27 20:26:25 +0200325procedure TPipeStreamBase.Flush;
Roger Meier3bef8c22012-10-06 06:58:00 +0000326begin
Jens Geyer0d227b12015-12-02 19:50:55 +0100327 FlushFileBuffers( FPipe);
Roger Meier3bef8c22012-10-06 06:58:00 +0000328end;
329
330
Jens Geyer06045cf2013-03-27 20:26:25 +0200331function TPipeStreamBase.IsOpen: Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000332begin
333 result := (FPipe <> INVALID_HANDLE_VALUE);
334end;
335
336
Jens Geyer17c3ad92017-09-05 20:31:27 +0200337procedure TPipeStreamBase.Write( const pBuf : Pointer; offset, count : Integer);
Jens Geyere9651362014-03-20 22:46:17 +0200338begin
339 if FOverlapped
Jens Geyer17c3ad92017-09-05 20:31:27 +0200340 then WriteOverlapped( pBuf, offset, count)
341 else WriteDirect( pBuf, offset, count);
Jens Geyere9651362014-03-20 22:46:17 +0200342end;
343
344
Jens Geyer17c3ad92017-09-05 20:31:27 +0200345function TPipeStreamBase.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyere9651362014-03-20 22:46:17 +0200346begin
347 if FOverlapped
Jens Geyer17c3ad92017-09-05 20:31:27 +0200348 then result := ReadOverlapped( pBuf, buflen, offset, count)
349 else result := ReadDirect( pBuf, buflen, offset, count);
Jens Geyere9651362014-03-20 22:46:17 +0200350end;
351
352
Jens Geyer17c3ad92017-09-05 20:31:27 +0200353procedure TPipeStreamBase.WriteDirect( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyerd4df9172017-10-25 22:30:23 +0200354var cbWritten, nBytes : DWORD;
Jens Geyer85827152018-01-12 21:20:59 +0100355 pData : PByte;
Roger Meier3bef8c22012-10-06 06:58:00 +0000356begin
357 if not IsOpen
Jens Geyere0e32402016-04-20 21:50:48 +0200358 then raise TTransportExceptionNotOpen.Create('Called write on non-open pipe');
Roger Meier3bef8c22012-10-06 06:58:00 +0000359
Jens Geyerd4df9172017-10-25 22:30:23 +0200360 // if necessary, send the data in chunks
361 // there's a system limit around 0x10000 bytes that we hit otherwise
362 // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
363 nBytes := Min( 15*4096, count); // 16 would exceed the limit
Jens Geyer85827152018-01-12 21:20:59 +0100364 pData := pBuf;
365 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200366 while nBytes > 0 do begin
Jens Geyer85827152018-01-12 21:20:59 +0100367 if not WriteFile( FPipe, pData^, nBytes, cbWritten, nil)
Jens Geyerd4df9172017-10-25 22:30:23 +0200368 then raise TTransportExceptionNotOpen.Create('Write to pipe failed');
369
Jens Geyer85827152018-01-12 21:20:59 +0100370 Inc( pData, cbWritten);
Jens Geyerd4df9172017-10-25 22:30:23 +0200371 Dec( count, cbWritten);
372 nBytes := Min( nBytes, count);
373 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000374end;
375
376
Jens Geyer17c3ad92017-09-05 20:31:27 +0200377procedure TPipeStreamBase.WriteOverlapped( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyerd4df9172017-10-25 22:30:23 +0200378var cbWritten, dwWait, dwError, nBytes : DWORD;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200379 overlapped : IOverlappedHelper;
Jens Geyer85827152018-01-12 21:20:59 +0100380 pData : PByte;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200381begin
382 if not IsOpen
383 then raise TTransportExceptionNotOpen.Create('Called write on non-open pipe');
384
Jens Geyerd4df9172017-10-25 22:30:23 +0200385 // if necessary, send the data in chunks
386 // there's a system limit around 0x10000 bytes that we hit otherwise
387 // MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
388 nBytes := Min( 15*4096, count); // 16 would exceed the limit
Jens Geyer85827152018-01-12 21:20:59 +0100389 pData := pBuf;
390 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200391 while nBytes > 0 do begin
392 overlapped := TOverlappedHelperImpl.Create;
Jens Geyer85827152018-01-12 21:20:59 +0100393 if not WriteFile( FPipe, pData^, nBytes, cbWritten, overlapped.OverlappedPtr)
Jens Geyerd4df9172017-10-25 22:30:23 +0200394 then begin
395 dwError := GetLastError;
396 case dwError of
397 ERROR_IO_PENDING : begin
398 dwWait := overlapped.WaitFor(FTimeout);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200399
Jens Geyer00645162018-02-01 23:38:10 +0100400 if (dwWait = WAIT_TIMEOUT) then begin
401 CancelIo( FPipe); // prevents possible AV on invalid overlapped ptr
402 raise TTransportExceptionTimedOut.Create('Pipe write timed out');
403 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200404
Jens Geyerd4df9172017-10-25 22:30:23 +0200405 if (dwWait <> WAIT_OBJECT_0)
406 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbWritten, TRUE)
407 then raise TTransportExceptionUnknown.Create('Pipe write error');
408 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200409
Jens Geyerd4df9172017-10-25 22:30:23 +0200410 else
411 raise TTransportExceptionUnknown.Create(SysErrorMessage(dwError));
Jens Geyer17c3ad92017-09-05 20:31:27 +0200412 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200413 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200414
Jens Geyerd4df9172017-10-25 22:30:23 +0200415 ASSERT( DWORD(nBytes) = cbWritten);
416
Jens Geyer85827152018-01-12 21:20:59 +0100417 Inc( pData, cbWritten);
Jens Geyerd4df9172017-10-25 22:30:23 +0200418 Dec( count, cbWritten);
419 nBytes := Min( nBytes, count);
420 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200421end;
422
423
424function TPipeStreamBase.ReadDirect( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd4df9172017-10-25 22:30:23 +0200425var cbRead, dwErr, nRemaining : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000426 bytes, retries : LongInt;
427 bOk : Boolean;
Jens Geyer85827152018-01-12 21:20:59 +0100428 pData : PByte;
Roger Meier3bef8c22012-10-06 06:58:00 +0000429const INTERVAL = 10; // ms
430begin
431 if not IsOpen
Jens Geyere0e32402016-04-20 21:50:48 +0200432 then raise TTransportExceptionNotOpen.Create('Called read on non-open pipe');
Roger Meier3bef8c22012-10-06 06:58:00 +0000433
434 // MSDN: Handle can be a handle to a named pipe instance,
435 // or it can be a handle to the read end of an anonymous pipe,
436 // The handle must have GENERIC_READ access to the pipe.
437 if FTimeOut <> INFINITE then begin
438 retries := Max( 1, Round( 1.0 * FTimeOut / INTERVAL));
439 while TRUE do begin
Jens Geyer5988f482016-04-19 23:01:24 +0200440 if not PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil) then begin
441 dwErr := GetLastError;
442 if (dwErr = ERROR_INVALID_HANDLE)
443 or (dwErr = ERROR_BROKEN_PIPE)
444 or (dwErr = ERROR_PIPE_NOT_CONNECTED)
445 then begin
446 result := 0; // other side closed the pipe
447 Exit;
448 end;
449 end
450 else if bytes > 0 then begin
451 Break; // there are data
Roger Meier79655fb2012-10-20 20:59:41 +0000452 end;
453
Roger Meier3bef8c22012-10-06 06:58:00 +0000454 Dec( retries);
455 if retries > 0
456 then Sleep( INTERVAL)
Jens Geyere0e32402016-04-20 21:50:48 +0200457 else raise TTransportExceptionTimedOut.Create('Pipe read timed out');
Roger Meier3bef8c22012-10-06 06:58:00 +0000458 end;
459 end;
460
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 // read the data (or block INFINITE-ly)
Jens Geyer85827152018-01-12 21:20:59 +0100467 bOk := ReadFile( FPipe, pData^, nRemaining, cbRead, nil);
Jens Geyerd4df9172017-10-25 22:30:23 +0200468 if (not bOk) and (GetLastError() <> ERROR_MORE_DATA)
469 then Break; // No more data, possibly because client disconnected.
470
471 Dec( nRemaining, cbRead);
Jens Geyer85827152018-01-12 21:20:59 +0100472 Inc( pData, cbRead);
Jens Geyerd4df9172017-10-25 22:30:23 +0200473 Inc( result, cbRead);
474 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000475end;
476
477
Jens Geyer17c3ad92017-09-05 20:31:27 +0200478function TPipeStreamBase.ReadOverlapped( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd4df9172017-10-25 22:30:23 +0200479var cbRead, dwWait, dwError, nRemaining : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +0200480 bOk : Boolean;
481 overlapped : IOverlappedHelper;
Jens Geyer85827152018-01-12 21:20:59 +0100482 pData : PByte;
Jens Geyere9651362014-03-20 22:46:17 +0200483begin
484 if not IsOpen
Jens Geyere0e32402016-04-20 21:50:48 +0200485 then raise TTransportExceptionNotOpen.Create('Called read on non-open pipe');
Jens Geyere9651362014-03-20 22:46:17 +0200486
Jens Geyerd4df9172017-10-25 22:30:23 +0200487 result := 0;
488 nRemaining := count;
Jens Geyer85827152018-01-12 21:20:59 +0100489 pData := pBuf;
490 Inc( pData, offset);
Jens Geyerd4df9172017-10-25 22:30:23 +0200491 while nRemaining > 0 do begin
492 overlapped := TOverlappedHelperImpl.Create;
Jens Geyere9651362014-03-20 22:46:17 +0200493
Jens Geyerd4df9172017-10-25 22:30:23 +0200494 // read the data
Jens Geyer85827152018-01-12 21:20:59 +0100495 bOk := ReadFile( FPipe, pData^, nRemaining, cbRead, overlapped.OverlappedPtr);
Jens Geyerd4df9172017-10-25 22:30:23 +0200496 if not bOk then begin
497 dwError := GetLastError;
498 case dwError of
499 ERROR_IO_PENDING : begin
500 dwWait := overlapped.WaitFor(FTimeout);
Jens Geyere9651362014-03-20 22:46:17 +0200501
Jens Geyer00645162018-02-01 23:38:10 +0100502 if (dwWait = WAIT_TIMEOUT) then begin
503 CancelIo( FPipe); // prevents possible AV on invalid overlapped ptr
504 raise TTransportExceptionTimedOut.Create('Pipe read timed out');
505 end;
Jens Geyere9651362014-03-20 22:46:17 +0200506
Jens Geyerd4df9172017-10-25 22:30:23 +0200507 if (dwWait <> WAIT_OBJECT_0)
508 or not GetOverlappedResult( FPipe, overlapped.Overlapped, cbRead, TRUE)
509 then raise TTransportExceptionUnknown.Create('Pipe read error');
510 end;
511
512 else
513 raise TTransportExceptionUnknown.Create(SysErrorMessage(dwError));
Jens Geyere9651362014-03-20 22:46:17 +0200514 end;
Jens Geyere9651362014-03-20 22:46:17 +0200515 end;
Jens Geyere9651362014-03-20 22:46:17 +0200516
Jens Geyerd4df9172017-10-25 22:30:23 +0200517 ASSERT( cbRead > 0); // see TTransportImpl.ReadAll()
518 ASSERT( cbRead <= DWORD(nRemaining));
519 Dec( nRemaining, cbRead);
Jens Geyer85827152018-01-12 21:20:59 +0100520 Inc( pData, cbRead);
Jens Geyerd4df9172017-10-25 22:30:23 +0200521 Inc( result, cbRead);
522 end;
Jens Geyere9651362014-03-20 22:46:17 +0200523end;
524
525
Jens Geyer06045cf2013-03-27 20:26:25 +0200526function TPipeStreamBase.ToArray: TBytes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000527var bytes : LongInt;
528begin
529 SetLength( result, 0);
530 bytes := 0;
531
532 if IsOpen
533 and PeekNamedPipe( FPipe, nil, 0, nil, @bytes, nil)
534 and (bytes > 0)
535 then begin
536 SetLength( result, bytes);
537 Read( result, 0, bytes);
538 end;
539end;
540
541
Roger Meier79655fb2012-10-20 20:59:41 +0000542{ TNamedPipeStreamImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000543
544
Jens Geyere9651362014-03-20 22:46:17 +0200545constructor TNamedPipeStreamImpl.Create( const aPipeName : string;
546 const aEnableOverlapped : Boolean;
547 const aShareMode: DWORD;
Roger Meier79655fb2012-10-20 20:59:41 +0000548 const aSecurityAttributes: PSecurityAttributes;
Jens Geyer653f0de2016-04-20 12:46:57 +0200549 const aTimeOut, aOpenTimeOut : DWORD);
Roger Meier3bef8c22012-10-06 06:58:00 +0000550begin
Jens Geyera019cda2019-11-09 23:24:52 +0100551 inherited Create( aEnableOverlapped, aTimeOut, aOpenTimeOut);
Roger Meier79655fb2012-10-20 20:59:41 +0000552
553 FPipeName := aPipeName;
554 FShareMode := aShareMode;
555 FSecurityAttribs := aSecurityAttributes;
556
557 if Copy(FPipeName,1,2) <> '\\'
558 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
Roger Meier3bef8c22012-10-06 06:58:00 +0000559end;
560
561
Roger Meier79655fb2012-10-20 20:59:41 +0000562procedure TNamedPipeStreamImpl.Open;
563var hPipe : THandle;
Jens Geyerb89b5b92016-04-19 23:09:41 +0200564 retries, timeout, dwErr : DWORD;
565const INTERVAL = 10; // ms
Roger Meier79655fb2012-10-20 20:59:41 +0000566begin
567 if IsOpen then Exit;
568
Jens Geyer653f0de2016-04-20 12:46:57 +0200569 retries := Max( 1, Round( 1.0 * FOpenTimeOut / INTERVAL));
570 timeout := FOpenTimeOut;
Jens Geyerb89b5b92016-04-19 23:09:41 +0200571
572 // if the server hasn't gotten to the point where the pipe has been created, at least wait the timeout
573 // According to MSDN, if no instances of the specified named pipe exist, the WaitNamedPipe function
574 // returns IMMEDIATELY, regardless of the time-out value.
Jens Geyer653f0de2016-04-20 12:46:57 +0200575 // Always use INTERVAL, since WaitNamedPipe(0) defaults to some other value
Jens Geyerb89b5b92016-04-19 23:09:41 +0200576 while not WaitNamedPipe( PChar(FPipeName), INTERVAL) do begin
577 dwErr := GetLastError;
578 if dwErr <> ERROR_FILE_NOT_FOUND
Jens Geyere0e32402016-04-20 21:50:48 +0200579 then raise TTransportExceptionNotOpen.Create('Unable to open pipe, '+SysErrorMessage(dwErr));
Jens Geyerb89b5b92016-04-19 23:09:41 +0200580
581 if timeout <> INFINITE then begin
582 if (retries > 0)
583 then Dec(retries)
Jens Geyere0e32402016-04-20 21:50:48 +0200584 else raise TTransportExceptionNotOpen.Create('Unable to open pipe, timed out');
Jens Geyerb89b5b92016-04-19 23:09:41 +0200585 end;
586
587 Sleep(INTERVAL)
588 end;
589
Roger Meier79655fb2012-10-20 20:59:41 +0000590 // open that thingy
Roger Meier79655fb2012-10-20 20:59:41 +0000591 hPipe := CreateFile( PChar( FPipeName),
592 GENERIC_READ or GENERIC_WRITE,
593 FShareMode, // sharing
594 FSecurityAttribs, // security attributes
595 OPEN_EXISTING, // opens existing pipe
Jens Geyere9651362014-03-20 22:46:17 +0200596 FILE_FLAG_OVERLAPPED or FILE_FLAG_WRITE_THROUGH, // async+fast, please
Roger Meier79655fb2012-10-20 20:59:41 +0000597 0); // no template file
598
599 if hPipe = INVALID_HANDLE_VALUE
Jens Geyere0e32402016-04-20 21:50:48 +0200600 then raise TTransportExceptionNotOpen.Create('Unable to open pipe, '+SysErrorMessage(GetLastError));
Roger Meier79655fb2012-10-20 20:59:41 +0000601
Roger Meier79655fb2012-10-20 20:59:41 +0000602 // everything fine
603 FPipe := hPipe;
604end;
605
606
607{ THandlePipeStreamImpl }
608
609
Jens Geyere9651362014-03-20 22:46:17 +0200610constructor THandlePipeStreamImpl.Create( const aPipeHandle : THandle;
611 const aOwnsHandle, aEnableOverlapped : Boolean;
612 const aTimeOut : DWORD);
Roger Meier79655fb2012-10-20 20:59:41 +0000613begin
Jens Geyera019cda2019-11-09 23:24:52 +0100614 inherited Create( aEnableOverlapped, aTimeout, aTimeout);
Roger Meier79655fb2012-10-20 20:59:41 +0000615
616 if aOwnsHandle
617 then FSrcHandle := aPipeHandle
618 else FSrcHandle := DuplicatePipeHandle( aPipeHandle);
619
620 Open;
621end;
622
623
624destructor THandlePipeStreamImpl.Destroy;
625begin
626 try
627 ClosePipeHandle( FSrcHandle);
628 finally
629 inherited Destroy;
630 end;
631end;
632
633
634procedure THandlePipeStreamImpl.Open;
635begin
636 if not IsOpen
637 then FPipe := DuplicatePipeHandle( FSrcHandle);
638end;
639
640
Jens Geyer06045cf2013-03-27 20:26:25 +0200641{ TPipeTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000642
643
Jens Geyer06045cf2013-03-27 20:26:25 +0200644function TPipeTransportBase.GetIsOpen: Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000645begin
Jens Geyer0b20cc82013-03-07 20:47:01 +0100646 result := (FInputStream <> nil) and (FInputStream.IsOpen)
647 and (FOutputStream <> nil) and (FOutputStream.IsOpen);
Roger Meier79655fb2012-10-20 20:59:41 +0000648end;
649
650
Jens Geyer06045cf2013-03-27 20:26:25 +0200651procedure TPipeTransportBase.Open;
Roger Meier79655fb2012-10-20 20:59:41 +0000652begin
653 FInputStream.Open;
654 FOutputStream.Open;
655end;
656
657
Jens Geyer06045cf2013-03-27 20:26:25 +0200658procedure TPipeTransportBase.Close;
Roger Meier79655fb2012-10-20 20:59:41 +0000659begin
660 FInputStream.Close;
661 FOutputStream.Close;
662end;
663
664
Jens Geyer06045cf2013-03-27 20:26:25 +0200665{ TNamedPipeTransportClientEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000666
667
Jens Geyera019cda2019-11-09 23:24:52 +0100668constructor TNamedPipeTransportClientEndImpl.Create( const aPipeName : string;
669 const aShareMode: DWORD;
Jens Geyer41f47af2019-11-09 23:24:52 +0100670 const aSecurityAttributes: PSecurityAttributes;
671 const aTimeOut, aOpenTimeOut : DWORD;
Jens Geyera019cda2019-11-09 23:24:52 +0100672 const aConfig : IThriftConfiguration);
Roger Meier3bef8c22012-10-06 06:58:00 +0000673// Named pipe constructor
674begin
Jens Geyera019cda2019-11-09 23:24:52 +0100675 inherited Create( nil, nil, aConfig);
Jens Geyer653f0de2016-04-20 12:46:57 +0200676 FInputStream := TNamedPipeStreamImpl.Create( aPipeName, TRUE, aShareMode, aSecurityAttributes, aTimeOut, aOpenTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000677 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000678end;
679
680
Jens Geyer41f47af2019-11-09 23:24:52 +0100681constructor TNamedPipeTransportClientEndImpl.Create( const aPipe : THandle;
682 const aOwnsHandle : Boolean;
683 const aTimeOut : DWORD;
Jens Geyera019cda2019-11-09 23:24:52 +0100684 const aConfig : IThriftConfiguration);
Roger Meier3bef8c22012-10-06 06:58:00 +0000685// Named pipe constructor
686begin
Jens Geyera019cda2019-11-09 23:24:52 +0100687 inherited Create( nil, nil, aConfig);
688 FInputStream := THandlePipeStreamImpl.Create( aPipe, aOwnsHandle, TRUE, aTimeOut);
Roger Meier3bef8c22012-10-06 06:58:00 +0000689 FOutputStream := FInputStream; // true for named pipes
Roger Meier3bef8c22012-10-06 06:58:00 +0000690end;
691
692
Jens Geyer06045cf2013-03-27 20:26:25 +0200693{ TNamedPipeTransportServerEndImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000694
695
Jens Geyer41f47af2019-11-09 23:24:52 +0100696constructor TNamedPipeTransportServerEndImpl.Create( const aPipe : THandle;
697 const aOwnsHandle : Boolean;
698 const aTimeOut : DWORD;
Jens Geyera019cda2019-11-09 23:24:52 +0100699 const aConfig : IThriftConfiguration);
Roger Meier79655fb2012-10-20 20:59:41 +0000700// Named pipe constructor
Roger Meier3bef8c22012-10-06 06:58:00 +0000701begin
Roger Meier79655fb2012-10-20 20:59:41 +0000702 FHandle := DuplicatePipeHandle( aPipe);
Jens Geyera019cda2019-11-09 23:24:52 +0100703 inherited Create( aPipe, aOwnsHandle, aTimeout, aConfig);
Roger Meier3bef8c22012-10-06 06:58:00 +0000704end;
705
706
Jens Geyer06045cf2013-03-27 20:26:25 +0200707procedure TNamedPipeTransportServerEndImpl.Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000708begin
Roger Meier79655fb2012-10-20 20:59:41 +0000709 FlushFileBuffers( FHandle);
710 DisconnectNamedPipe( FHandle); // force client off the pipe
711 ClosePipeHandle( FHandle);
Roger Meier3bef8c22012-10-06 06:58:00 +0000712
Roger Meier79655fb2012-10-20 20:59:41 +0000713 inherited Close;
Roger Meier3bef8c22012-10-06 06:58:00 +0000714end;
715
716
Jens Geyer06045cf2013-03-27 20:26:25 +0200717{ TAnonymousPipeTransportImpl }
Roger Meier3bef8c22012-10-06 06:58:00 +0000718
719
Jens Geyerdd074e72016-04-19 23:31:33 +0200720constructor TAnonymousPipeTransportImpl.Create( const aPipeRead, aPipeWrite : THandle;
Jens Geyer41f47af2019-11-09 23:24:52 +0100721 const aOwnsHandles : Boolean;
722 const aTimeOut : DWORD;
Jens Geyera019cda2019-11-09 23:24:52 +0100723 const aConfig : IThriftConfiguration);
Roger Meier3bef8c22012-10-06 06:58:00 +0000724// Anonymous pipe constructor
725begin
Jens Geyera019cda2019-11-09 23:24:52 +0100726 inherited Create( nil, nil, aConfig);
Jens Geyere9651362014-03-20 22:46:17 +0200727 // overlapped is not supported with AnonPipes, see MSDN
Jens Geyera019cda2019-11-09 23:24:52 +0100728 FInputStream := THandlePipeStreamImpl.Create( aPipeRead, aOwnsHandles, FALSE, aTimeout);
729 FOutputStream := THandlePipeStreamImpl.Create( aPipeWrite, aOwnsHandles, FALSE, aTimeout);
Roger Meier3bef8c22012-10-06 06:58:00 +0000730end;
731
732
Jens Geyer06045cf2013-03-27 20:26:25 +0200733{ TPipeServerTransportBase }
Roger Meier79655fb2012-10-20 20:59:41 +0000734
735
Jens Geyera019cda2019-11-09 23:24:52 +0100736constructor TPipeServerTransportBase.Create( const aConfig : IThriftConfiguration);
Jens Geyere9651362014-03-20 22:46:17 +0200737begin
Jens Geyera019cda2019-11-09 23:24:52 +0100738 inherited Create( aConfig);
Jens Geyere9651362014-03-20 22:46:17 +0200739 FStopServer := TEvent.Create(nil,TRUE,FALSE,''); // manual reset
740end;
741
742
743destructor TPipeServerTransportBase.Destroy;
744begin
745 try
746 FreeAndNil( FStopServer);
747 finally
748 inherited Destroy;
749 end;
750end;
751
752
753function TPipeServerTransportBase.QueryStopServer : Boolean;
754begin
755 result := (FStopServer = nil)
756 or (FStopServer.WaitFor(0) <> wrTimeout);
757end;
758
759
Jens Geyer06045cf2013-03-27 20:26:25 +0200760procedure TPipeServerTransportBase.Listen;
Roger Meier3bef8c22012-10-06 06:58:00 +0000761begin
Jens Geyere9651362014-03-20 22:46:17 +0200762 FStopServer.ResetEvent;
Roger Meier3bef8c22012-10-06 06:58:00 +0000763end;
764
765
Jens Geyer06045cf2013-03-27 20:26:25 +0200766procedure TPipeServerTransportBase.Close;
767begin
Jens Geyere9651362014-03-20 22:46:17 +0200768 FStopServer.SetEvent;
Jens Geyer06045cf2013-03-27 20:26:25 +0200769 InternalClose;
770end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000771
772
Jens Geyer06045cf2013-03-27 20:26:25 +0200773{ TAnonymousPipeServerTransportImpl }
774
Jens Geyera019cda2019-11-09 23:24:52 +0100775constructor TAnonymousPipeServerTransportImpl.Create( const aBufsize : Cardinal;
776 const aTimeOut : DWORD;
777 const aConfig : IThriftConfiguration);
Roger Meier3bef8c22012-10-06 06:58:00 +0000778// Anonymous pipe CTOR
779begin
Jens Geyera019cda2019-11-09 23:24:52 +0100780 inherited Create(aConfig);
Roger Meier3bef8c22012-10-06 06:58:00 +0000781 FBufsize := aBufSize;
Roger Meier79655fb2012-10-20 20:59:41 +0000782 FReadHandle := INVALID_HANDLE_VALUE;
Roger Meier3bef8c22012-10-06 06:58:00 +0000783 FWriteHandle := INVALID_HANDLE_VALUE;
784 FClientAnonRead := INVALID_HANDLE_VALUE;
785 FClientAnonWrite := INVALID_HANDLE_VALUE;
Jens Geyerdd074e72016-04-19 23:31:33 +0200786 FTimeOut := aTimeOut;
Roger Meier3bef8c22012-10-06 06:58:00 +0000787
788 // The anonymous pipe needs to be created first so that the server can
789 // pass the handles on to the client before the serve (acceptImpl)
790 // blocking call.
791 if not CreateAnonPipe
Jens Geyere0e32402016-04-20 21:50:48 +0200792 then raise TTransportExceptionNotOpen.Create(ClassName+'.Create() failed');
Roger Meier3bef8c22012-10-06 06:58:00 +0000793end;
794
795
Jens Geyer01640402013-09-25 21:12:21 +0200796function TAnonymousPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Roger Meier3bef8c22012-10-06 06:58:00 +0000797var buf : Byte;
798 br : DWORD;
Roger Meier3bef8c22012-10-06 06:58:00 +0000799begin
Jens Geyer01640402013-09-25 21:12:21 +0200800 if Assigned(fnAccepting)
801 then fnAccepting();
802
Roger Meier79655fb2012-10-20 20:59:41 +0000803 // This 0-byte read serves merely as a blocking call.
804 if not ReadFile( FReadHandle, buf, 0, br, nil)
805 and (GetLastError() <> ERROR_MORE_DATA)
Jens Geyere0e32402016-04-20 21:50:48 +0200806 then raise TTransportExceptionNotOpen.Create('TServerPipe unable to initiate pipe communication');
Jens Geyer06045cf2013-03-27 20:26:25 +0200807
808 // create the transport impl
Jens Geyera019cda2019-11-09 23:24:52 +0100809 result := TAnonymousPipeTransportImpl.Create( FReadHandle, FWriteHandle, FALSE, FTimeOut, Configuration);
Roger Meier3bef8c22012-10-06 06:58:00 +0000810end;
811
812
Jens Geyer06045cf2013-03-27 20:26:25 +0200813procedure TAnonymousPipeServerTransportImpl.InternalClose;
Roger Meier3bef8c22012-10-06 06:58:00 +0000814begin
Roger Meier79655fb2012-10-20 20:59:41 +0000815 ClosePipeHandle( FReadHandle);
816 ClosePipeHandle( FWriteHandle);
817 ClosePipeHandle( FClientAnonRead);
818 ClosePipeHandle( FClientAnonWrite);
Roger Meier3bef8c22012-10-06 06:58:00 +0000819end;
820
821
Jens Geyer06045cf2013-03-27 20:26:25 +0200822function TAnonymousPipeServerTransportImpl.ReadHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000823begin
Roger Meier79655fb2012-10-20 20:59:41 +0000824 result := FReadHandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000825end;
826
827
Jens Geyer06045cf2013-03-27 20:26:25 +0200828function TAnonymousPipeServerTransportImpl.WriteHandle : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000829begin
830 result := FWriteHandle;
831end;
832
833
Jens Geyer06045cf2013-03-27 20:26:25 +0200834function TAnonymousPipeServerTransportImpl.ClientAnonRead : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000835begin
836 result := FClientAnonRead;
837end;
838
839
Jens Geyer06045cf2013-03-27 20:26:25 +0200840function TAnonymousPipeServerTransportImpl.ClientAnonWrite : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +0000841begin
842 result := FClientAnonWrite;
843end;
844
845
Jens Geyer06045cf2013-03-27 20:26:25 +0200846function TAnonymousPipeServerTransportImpl.CreateAnonPipe : Boolean;
Roger Meier79655fb2012-10-20 20:59:41 +0000847var sd : PSECURITY_DESCRIPTOR;
848 sa : SECURITY_ATTRIBUTES; //TSecurityAttributes;
849 hCAR, hPipeW, hCAW, hPipe : THandle;
850begin
Roger Meier79655fb2012-10-20 20:59:41 +0000851 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
Jens Geyerb64a7742013-01-23 20:58:47 +0100852 try
853 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
854 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, nil, FALSE));
Roger Meier79655fb2012-10-20 20:59:41 +0000855
Jens Geyerb64a7742013-01-23 20:58:47 +0100856 sa.nLength := sizeof( sa);
857 sa.lpSecurityDescriptor := sd;
858 sa.bInheritHandle := TRUE; //allow passing handle to child
Roger Meier79655fb2012-10-20 20:59:41 +0000859
Jens Geyer17c3ad92017-09-05 20:31:27 +0200860 Result := CreatePipe( hCAR, hPipeW, @sa, FBufSize); //create stdin pipe
861 if not Result then begin //create stdin pipe
Jens Geyere0e32402016-04-20 21:50:48 +0200862 raise TTransportExceptionNotOpen.Create('TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100863 Exit;
864 end;
865
Jens Geyer17c3ad92017-09-05 20:31:27 +0200866 Result := CreatePipe( hPipe, hCAW, @sa, FBufSize); //create stdout pipe
867 if not Result then begin //create stdout pipe
Jens Geyerb64a7742013-01-23 20:58:47 +0100868 CloseHandle( hCAR);
869 CloseHandle( hPipeW);
Jens Geyere0e32402016-04-20 21:50:48 +0200870 raise TTransportExceptionNotOpen.Create('TServerPipe CreatePipe (anon) failed, '+SysErrorMessage(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +0100871 Exit;
872 end;
873
874 FClientAnonRead := hCAR;
875 FClientAnonWrite := hCAW;
876 FReadHandle := hPipe;
877 FWriteHandle := hPipeW;
Jens Geyerb64a7742013-01-23 20:58:47 +0100878 finally
879 if sd <> nil then LocalFree( Cardinal(sd));
Roger Meier79655fb2012-10-20 20:59:41 +0000880 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000881end;
882
883
Jens Geyer06045cf2013-03-27 20:26:25 +0200884{ TNamedPipeServerTransportImpl }
Roger Meier79655fb2012-10-20 20:59:41 +0000885
886
Jens Geyera019cda2019-11-09 23:24:52 +0100887constructor TNamedPipeServerTransportImpl.Create( const aPipename : string;
888 const aBufsize, aMaxConns, aTimeOut : Cardinal;
889 const aConfig : IThriftConfiguration);
Roger Meier79655fb2012-10-20 20:59:41 +0000890// Named Pipe CTOR
891begin
Jens Geyera019cda2019-11-09 23:24:52 +0100892 inherited Create( aConfig);
Jens Geyer06045cf2013-03-27 20:26:25 +0200893 FPipeName := aPipename;
894 FBufsize := aBufSize;
895 FMaxConns := Max( 1, Min( PIPE_UNLIMITED_INSTANCES, aMaxConns));
896 FHandle := INVALID_HANDLE_VALUE;
897 FTimeout := aTimeOut;
898 FConnected := FALSE;
Jens Geyera019cda2019-11-09 23:24:52 +0100899 ASSERT( FTimeout > 0);
Roger Meier79655fb2012-10-20 20:59:41 +0000900
901 if Copy(FPipeName,1,2) <> '\\'
902 then FPipeName := '\\.\pipe\' + FPipeName; // assume localhost
903end;
904
905
Jens Geyer01640402013-09-25 21:12:21 +0200906function TNamedPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
Jens Geyer06045cf2013-03-27 20:26:25 +0200907var dwError, dwWait, dwDummy : DWORD;
Jens Geyere9651362014-03-20 22:46:17 +0200908 overlapped : IOverlappedHelper;
909 handles : array[0..1] of THandle;
Jens Geyer01640402013-09-25 21:12:21 +0200910begin
Jens Geyere9651362014-03-20 22:46:17 +0200911 overlapped := TOverlappedHelperImpl.Create;
Jens Geyer01640402013-09-25 21:12:21 +0200912
Jens Geyere9651362014-03-20 22:46:17 +0200913 ASSERT( not FConnected);
Jens Geyer2ad6c302015-02-26 19:38:53 +0100914 CreateNamedPipe;
Jens Geyere9651362014-03-20 22:46:17 +0200915 while not FConnected do begin
Jens Geyer2ad6c302015-02-26 19:38:53 +0100916
Jens Geyer00645162018-02-01 23:38:10 +0100917 if QueryStopServer then begin
918 InternalClose;
919 Abort;
920 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000921
Jens Geyere9651362014-03-20 22:46:17 +0200922 if Assigned(fnAccepting)
923 then fnAccepting();
Jens Geyer01640402013-09-25 21:12:21 +0200924
Jens Geyere9651362014-03-20 22:46:17 +0200925 // Wait for the client to connect; if it succeeds, the
926 // function returns a nonzero value. If the function returns
927 // zero, GetLastError should return ERROR_PIPE_CONNECTED.
928 if ConnectNamedPipe( Handle, overlapped.OverlappedPtr) then begin
929 FConnected := TRUE;
930 Break;
Jens Geyer01640402013-09-25 21:12:21 +0200931 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000932
Jens Geyere9651362014-03-20 22:46:17 +0200933 // ConnectNamedPipe() returns FALSE for OverlappedIO, even if connected.
934 // We have to check GetLastError() explicitly to find out
935 dwError := GetLastError;
936 case dwError of
937 ERROR_PIPE_CONNECTED : begin
938 FConnected := not QueryStopServer; // special case: pipe immediately connected
939 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000940
Jens Geyere9651362014-03-20 22:46:17 +0200941 ERROR_IO_PENDING : begin
942 handles[0] := overlapped.WaitHandle;
943 handles[1] := FStopServer.Handle;
944 dwWait := WaitForMultipleObjects( 2, @handles, FALSE, FTimeout);
945 FConnected := (dwWait = WAIT_OBJECT_0)
946 and GetOverlappedResult( Handle, overlapped.Overlapped, dwDummy, TRUE)
947 and not QueryStopServer;
948 end;
949
950 else
951 InternalClose;
Jens Geyere0e32402016-04-20 21:50:48 +0200952 raise TTransportExceptionNotOpen.Create('Client connection failed');
Jens Geyere9651362014-03-20 22:46:17 +0200953 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000954 end;
Jens Geyere9651362014-03-20 22:46:17 +0200955
956 // create the transport impl
957 result := CreateTransportInstance;
Roger Meier79655fb2012-10-20 20:59:41 +0000958end;
959
960
Jens Geyer06045cf2013-03-27 20:26:25 +0200961function TNamedPipeServerTransportImpl.CreateTransportInstance : ITransport;
962// create the transport impl
963var hPipe : THandle;
Roger Meier79655fb2012-10-20 20:59:41 +0000964begin
Jens Geyer06045cf2013-03-27 20:26:25 +0200965 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
966 try
967 FConnected := FALSE;
Jens Geyera019cda2019-11-09 23:24:52 +0100968 result := TNamedPipeTransportServerEndImpl.Create( hPipe, TRUE, FTimeout, Configuration);
Jens Geyer06045cf2013-03-27 20:26:25 +0200969 except
Jens Geyer01640402013-09-25 21:12:21 +0200970 ClosePipeHandle(hPipe);
971 raise;
972 end;
Roger Meier79655fb2012-10-20 20:59:41 +0000973end;
974
975
Jens Geyer06045cf2013-03-27 20:26:25 +0200976procedure TNamedPipeServerTransportImpl.InternalClose;
977var hPipe : THandle;
978begin
979 hPipe := THandle( InterlockedExchangePointer( Pointer(FHandle), Pointer(INVALID_HANDLE_VALUE)));
980 if hPipe = INVALID_HANDLE_VALUE then Exit;
981
982 try
983 if FConnected
984 then FlushFileBuffers( hPipe)
985 else CancelIo( hPipe);
986 DisconnectNamedPipe( hPipe);
987 finally
988 ClosePipeHandle( hPipe);
989 FConnected := FALSE;
990 end;
991end;
992
993
994function TNamedPipeServerTransportImpl.Handle : THandle;
995begin
996 {$IFDEF WIN64}
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200997 result := THandle( InterlockedExchangeAdd64( Int64(FHandle), 0));
Jens Geyer06045cf2013-03-27 20:26:25 +0200998 {$ELSE}
999 result := THandle( InterlockedExchangeAdd( Integer(FHandle), 0));
1000 {$ENDIF}
1001end;
1002
1003
1004function TNamedPipeServerTransportImpl.CreateNamedPipe : THandle;
Roger Meier3bef8c22012-10-06 06:58:00 +00001005var SIDAuthWorld : SID_IDENTIFIER_AUTHORITY ;
1006 everyone_sid : PSID;
1007 ea : EXPLICIT_ACCESS;
1008 acl : PACL;
1009 sd : PSECURITY_DESCRIPTOR;
1010 sa : SECURITY_ATTRIBUTES;
Roger Meier3bef8c22012-10-06 06:58:00 +00001011const
1012 SECURITY_WORLD_SID_AUTHORITY : TSIDIdentifierAuthority = (Value : (0,0,0,0,0,1));
1013 SECURITY_WORLD_RID = $00000000;
1014begin
Jens Geyerb64a7742013-01-23 20:58:47 +01001015 sd := nil;
Roger Meier3bef8c22012-10-06 06:58:00 +00001016 everyone_sid := nil;
Jens Geyerb64a7742013-01-23 20:58:47 +01001017 try
Jens Geyer06045cf2013-03-27 20:26:25 +02001018 ASSERT( (FHandle = INVALID_HANDLE_VALUE) and not FConnected);
1019
Jens Geyerb64a7742013-01-23 20:58:47 +01001020 // Windows - set security to allow non-elevated apps
1021 // to access pipes created by elevated apps.
1022 SIDAuthWorld := SECURITY_WORLD_SID_AUTHORITY;
1023 AllocateAndInitializeSid( SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +00001024
Jens Geyerb64a7742013-01-23 20:58:47 +01001025 ZeroMemory( @ea, SizeOf(ea));
1026 ea.grfAccessPermissions := GENERIC_ALL; //SPECIFIC_RIGHTS_ALL or STANDARD_RIGHTS_ALL;
1027 ea.grfAccessMode := SET_ACCESS;
1028 ea.grfInheritance := NO_INHERITANCE;
1029 ea.Trustee.TrusteeForm := TRUSTEE_IS_SID;
1030 ea.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
1031 ea.Trustee.ptstrName := PChar(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +00001032
Jens Geyerb64a7742013-01-23 20:58:47 +01001033 acl := nil;
1034 SetEntriesInAcl( 1, @ea, nil, acl);
Roger Meier3bef8c22012-10-06 06:58:00 +00001035
Jens Geyerb64a7742013-01-23 20:58:47 +01001036 sd := PSECURITY_DESCRIPTOR( LocalAlloc( LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
1037 Win32Check( InitializeSecurityDescriptor( sd, SECURITY_DESCRIPTOR_REVISION));
1038 Win32Check( SetSecurityDescriptorDacl( sd, TRUE, acl, FALSE));
Roger Meier3bef8c22012-10-06 06:58:00 +00001039
Jens Geyerb64a7742013-01-23 20:58:47 +01001040 sa.nLength := SizeOf(sa);
1041 sa.lpSecurityDescriptor := sd;
1042 sa.bInheritHandle := FALSE;
Roger Meier3bef8c22012-10-06 06:58:00 +00001043
Jens Geyerb64a7742013-01-23 20:58:47 +01001044 // Create an instance of the named pipe
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001045 {$IFDEF OLD_UNIT_NAMES}
1046 result := Windows.CreateNamedPipe(
1047 {$ELSE}
1048 result := Winapi.Windows.CreateNamedPipe(
1049 {$ENDIF}
1050 PChar( FPipeName), // pipe name
1051 PIPE_ACCESS_DUPLEX or // read/write access
1052 FILE_FLAG_OVERLAPPED, // async mode
1053 PIPE_TYPE_BYTE or // byte type pipe
1054 PIPE_READMODE_BYTE, // byte read mode
1055 FMaxConns, // max. instances
1056 FBufSize, // output buffer size
1057 FBufSize, // input buffer size
1058 FTimeout, // time-out, see MSDN
1059 @sa // default security attribute
1060 );
Roger Meier3bef8c22012-10-06 06:58:00 +00001061
Jens Geyer06045cf2013-03-27 20:26:25 +02001062 if( result <> INVALID_HANDLE_VALUE)
1063 then InterlockedExchangePointer( Pointer(FHandle), Pointer(result))
Jens Geyere0e32402016-04-20 21:50:48 +02001064 else raise TTransportExceptionNotOpen.Create('CreateNamedPipe() failed ' + IntToStr(GetLastError));
Jens Geyerb64a7742013-01-23 20:58:47 +01001065
1066 finally
1067 if sd <> nil then LocalFree( Cardinal( sd));
1068 if acl <> nil then LocalFree( Cardinal( acl));
1069 if everyone_sid <> nil then FreeSid(everyone_sid);
Roger Meier3bef8c22012-10-06 06:58:00 +00001070 end;
Roger Meier3bef8c22012-10-06 06:58:00 +00001071end;
1072
1073
Roger Meier3bef8c22012-10-06 06:58:00 +00001074
1075end.
1076
1077
1078