blob: 6f9a93d64d660111ff361a27cda4cd8dbe22b624 [file] [log] [blame]
Jens Geyerd5436f52014-10-03 19:50:38 +02001(*
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 *)
Jens Geyerd5436f52014-10-03 19:50:38 +020019unit Thrift.Transport;
20
Jens Geyer9f7f11e2016-04-14 21:37:11 +020021{$I Thrift.Defines.inc}
22{$SCOPEDENUMS ON}
23
Jens Geyerd5436f52014-10-03 19:50:38 +020024interface
25
26uses
27 Classes,
28 SysUtils,
29 Math,
Jens Geyerd5436f52014-10-03 19:50:38 +020030 Generics.Collections,
Jens Geyer9f7f11e2016-04-14 21:37:11 +020031 {$IFDEF OLD_UNIT_NAMES}
Jens Geyer02230912019-04-03 01:12:51 +020032 WinSock, Sockets,
Nick4f5229e2016-04-14 16:43:22 +030033 {$ELSE}
Jens Geyer02230912019-04-03 01:12:51 +020034 Winapi.WinSock,
Jens Geyer9f7f11e2016-04-14 21:37:11 +020035 {$IFDEF OLD_SOCKETS}
Jens Geyerbea9bbe2016-04-20 00:02:40 +020036 Web.Win.Sockets,
37 {$ELSE}
38 Thrift.Socket,
Jens Geyer9f7f11e2016-04-14 21:37:11 +020039 {$ENDIF}
40 {$ENDIF}
Jens Geyera019cda2019-11-09 23:24:52 +010041 Thrift.Configuration,
Jens Geyerd5436f52014-10-03 19:50:38 +020042 Thrift.Collections,
Jens Geyer606f1ef2018-04-09 23:09:41 +020043 Thrift.Exception,
Jens Geyerd5436f52014-10-03 19:50:38 +020044 Thrift.Utils,
Jens Geyer02230912019-04-03 01:12:51 +020045 Thrift.WinHTTP,
Nick4f5229e2016-04-14 16:43:22 +030046 Thrift.Stream;
Jens Geyerd5436f52014-10-03 19:50:38 +020047
48type
Jens Geyera019cda2019-11-09 23:24:52 +010049 IStreamTransport = interface;
Jens Geyer41f47af2019-11-09 23:24:52 +010050
Jens Geyerd5436f52014-10-03 19:50:38 +020051 ITransport = interface
Jens Geyera019cda2019-11-09 23:24:52 +010052 ['{52F81383-F880-492F-8AA7-A66B85B93D6B}']
Jens Geyerd5436f52014-10-03 19:50:38 +020053 function GetIsOpen: Boolean;
54 property IsOpen: Boolean read GetIsOpen;
55 function Peek: Boolean;
56 procedure Open;
57 procedure Close;
Jens Geyer41f47af2019-11-09 23:24:52 +010058
Jens Geyer17c3ad92017-09-05 20:31:27 +020059 function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
60 function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
61 function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
62 function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020063 procedure Write( const buf: TBytes); overload;
64 procedure Write( const buf: TBytes; off: Integer; len: Integer); overload;
Jens Geyer17c3ad92017-09-05 20:31:27 +020065 procedure Write( const pBuf : Pointer; off, len : Integer); overload;
66 procedure Write( const pBuf : Pointer; len : Integer); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020067 procedure Flush;
Jens Geyer41f47af2019-11-09 23:24:52 +010068
Jens Geyera019cda2019-11-09 23:24:52 +010069 function Configuration : IThriftConfiguration;
70 function MaxMessageSize : Integer;
Jens Geyer5a781c22025-02-04 23:35:55 +010071 procedure ResetMessageSizeAndConsumedBytes( const knownSize : Int64 = -1);
Jens Geyera019cda2019-11-09 23:24:52 +010072 procedure CheckReadBytesAvailable( const numBytes : Int64);
73 procedure UpdateKnownMessageSize( const size : Int64);
Jens Geyerd5436f52014-10-03 19:50:38 +020074 end;
75
Jens Geyera019cda2019-11-09 23:24:52 +010076 TTransportBase = class abstract( TInterfacedObject)
Jens Geyerfad7fd32019-11-09 23:24:52 +010077 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +020078 function GetIsOpen: Boolean; virtual; abstract;
79 property IsOpen: Boolean read GetIsOpen;
80 function Peek: Boolean; virtual;
81 procedure Open(); virtual; abstract;
82 procedure Close(); virtual; abstract;
Jens Geyer41f47af2019-11-09 23:24:52 +010083
Jens Geyer17c3ad92017-09-05 20:31:27 +020084 function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
85 function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual; abstract;
86 function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
87 function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual;
88 procedure Write( const buf: TBytes); overload; inline;
89 procedure Write( const buf: TBytes; off: Integer; len: Integer); overload; inline;
90 procedure Write( const pBuf : Pointer; len : Integer); overload; inline;
91 procedure Write( const pBuf : Pointer; off, len : Integer); overload; virtual; abstract;
Jens Geyerd5436f52014-10-03 19:50:38 +020092 procedure Flush; virtual;
Jens Geyer41f47af2019-11-09 23:24:52 +010093
Jens Geyera019cda2019-11-09 23:24:52 +010094 function Configuration : IThriftConfiguration; virtual; abstract;
95 procedure UpdateKnownMessageSize( const size : Int64); virtual; abstract;
96 end;
Jens Geyer41f47af2019-11-09 23:24:52 +010097
Jens Geyera019cda2019-11-09 23:24:52 +010098 // base class for all endpoint transports, e.g. sockets, pipes or HTTP
99 TEndpointTransportBase = class abstract( TTransportBase, ITransport)
100 strict private
101 FRemainingMessageSize : Int64;
102 FKnownMessageSize : Int64;
103 FConfiguration : IThriftConfiguration;
104 strict protected
105 function Configuration : IThriftConfiguration; override;
106 function MaxMessageSize : Integer;
107 property RemainingMessageSize : Int64 read FRemainingMessageSize;
108 property KnownMessageSize : Int64 read FKnownMessageSize;
Jens Geyer5a781c22025-02-04 23:35:55 +0100109 procedure ResetMessageSizeAndConsumedBytes( const newSize : Int64 = -1);
Jens Geyera019cda2019-11-09 23:24:52 +0100110 procedure UpdateKnownMessageSize(const size : Int64); override;
Jens Geyer5a781c22025-02-04 23:35:55 +0100111 procedure CheckReadBytesAvailable(const numBytes : Int64); {$IFNDEF Debug} inline; {$ENDIF}
112 procedure CountConsumedMessageBytes(const numBytes : Int64); {$IFNDEF Debug} inline; {$ENDIF}
Jens Geyer41f47af2019-11-09 23:24:52 +0100113 public
Jens Geyera019cda2019-11-09 23:24:52 +0100114 constructor Create( const aConfig : IThriftConfiguration); reintroduce;
115 end;
116
117 // base class for all layered transports, e.g. framed
118 TLayeredTransportBase<T : ITransport> = class abstract( TTransportBase, ITransport)
119 strict private
120 FTransport : T;
121 strict protected
122 property InnerTransport : T read FTransport;
123 function GetUnderlyingTransport: ITransport;
124 function Configuration : IThriftConfiguration; override;
125 procedure UpdateKnownMessageSize( const size : Int64); override;
126 function MaxMessageSize : Integer; inline;
Jens Geyer5a781c22025-02-04 23:35:55 +0100127 procedure ResetMessageSizeAndConsumedBytes( const knownSize : Int64 = -1); inline;
Jens Geyera019cda2019-11-09 23:24:52 +0100128 procedure CheckReadBytesAvailable( const numBytes : Int64); virtual;
129 public
130 constructor Create( const aTransport: T); reintroduce;
131 property UnderlyingTransport: ITransport read GetUnderlyingTransport;
Jens Geyerd5436f52014-10-03 19:50:38 +0200132 end;
133
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100134 TTransportException = class abstract( TException)
Jens Geyerd5436f52014-10-03 19:50:38 +0200135 public
136 type
137 TExceptionType = (
138 Unknown,
139 NotOpen,
140 AlreadyOpen,
141 TimedOut,
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200142 EndOfFile,
143 BadArgs,
Jens Geyer2646bd62019-11-09 23:24:52 +0100144 Interrupted,
145 CorruptedData
Jens Geyerd5436f52014-10-03 19:50:38 +0200146 );
Jens Geyerfad7fd32019-11-09 23:24:52 +0100147 strict protected
Jens Geyere0e32402016-04-20 21:50:48 +0200148 constructor HiddenCreate(const Msg: string);
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100149 class function GetType: TExceptionType; virtual; abstract;
Jens Geyerd5436f52014-10-03 19:50:38 +0200150 public
Jens Geyer41f47af2019-11-09 23:24:52 +0100151 class function Create( aType: TExceptionType): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
Jens Geyere0e32402016-04-20 21:50:48 +0200152 class function Create( const msg: string): TTransportException; reintroduce; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
Jens Geyer41f47af2019-11-09 23:24:52 +0100153 class function Create( aType: TExceptionType; const msg: string): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
Jens Geyere0e32402016-04-20 21:50:48 +0200154 property Type_: TExceptionType read GetType;
Jens Geyerd5436f52014-10-03 19:50:38 +0200155 end;
156
Jens Geyere0e32402016-04-20 21:50:48 +0200157 // Needed to remove deprecation warning
158 TTransportExceptionSpecialized = class abstract (TTransportException)
159 public
160 constructor Create(const Msg: string);
161 end;
162
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100163 TTransportExceptionUnknown = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100164 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100165 class function GetType: TTransportException.TExceptionType; override;
166 end;
167
168 TTransportExceptionNotOpen = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100169 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100170 class function GetType: TTransportException.TExceptionType; override;
171 end;
172
173 TTransportExceptionAlreadyOpen = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100174 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100175 class function GetType: TTransportException.TExceptionType; override;
176 end;
177
178 TTransportExceptionTimedOut = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100179 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100180 class function GetType: TTransportException.TExceptionType; override;
181 end;
182
183 TTransportExceptionEndOfFile = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100184 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100185 class function GetType: TTransportException.TExceptionType; override;
186 end;
187
188 TTransportExceptionBadArgs = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100189 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100190 class function GetType: TTransportException.TExceptionType; override;
191 end;
192
193 TTransportExceptionInterrupted = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100194 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100195 class function GetType: TTransportException.TExceptionType; override;
196 end;
Jens Geyere0e32402016-04-20 21:50:48 +0200197
Jens Geyer2646bd62019-11-09 23:24:52 +0100198 TTransportExceptionCorruptedData = class (TTransportExceptionSpecialized)
199 protected
200 class function GetType: TTransportException.TExceptionType; override;
201 end;
202
Jens Geyer47f63172019-06-06 22:42:58 +0200203 TSecureProtocol = (
fcprete28113f42025-06-10 02:54:38 +0200204 // outdated, for compatibility only
205 SSL_2,
206 SSL_3,
207 TLS_1,
208 TLS_1_1,
209 // secure (as of today)
210 TLS_1_2,
211 TLS_1_3
Jens Geyer47f63172019-06-06 22:42:58 +0200212 );
213
214 TSecureProtocols = set of TSecureProtocol;
215
Jens Geyerd5436f52014-10-03 19:50:38 +0200216 IHTTPClient = interface( ITransport )
Jens Geyer47f63172019-06-06 22:42:58 +0200217 ['{7BF615DD-8680-4004-A5B2-88947BA3BA3D}']
Jens Geyer20e727e2018-06-22 22:39:57 +0200218 procedure SetDnsResolveTimeout(const Value: Integer);
219 function GetDnsResolveTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200220 procedure SetConnectionTimeout(const Value: Integer);
221 function GetConnectionTimeout: Integer;
Jens Geyer20e727e2018-06-22 22:39:57 +0200222 procedure SetSendTimeout(const Value: Integer);
223 function GetSendTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200224 procedure SetReadTimeout(const Value: Integer);
225 function GetReadTimeout: Integer;
226 function GetCustomHeaders: IThriftDictionary<string,string>;
227 procedure SendRequest;
Jens Geyer47f63172019-06-06 22:42:58 +0200228 function GetSecureProtocols : TSecureProtocols;
229 procedure SetSecureProtocols( const value : TSecureProtocols);
Jens Geyer20e727e2018-06-22 22:39:57 +0200230
231 property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200232 property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
Jens Geyer20e727e2018-06-22 22:39:57 +0200233 property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200234 property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
235 property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
Jens Geyer47f63172019-06-06 22:42:58 +0200236 property SecureProtocols : TSecureProtocols read GetSecureProtocols write SetSecureProtocols;
Jens Geyerd5436f52014-10-03 19:50:38 +0200237 end;
238
Jens Geyerd5436f52014-10-03 19:50:38 +0200239 IServerTransport = interface
Jens Geyera019cda2019-11-09 23:24:52 +0100240 ['{FA01363F-6B40-482F-971E-4A085535EFC8}']
Jens Geyerd5436f52014-10-03 19:50:38 +0200241 procedure Listen;
242 procedure Close;
243 function Accept( const fnAccepting: TProc): ITransport;
Jens Geyera019cda2019-11-09 23:24:52 +0100244 function Configuration : IThriftConfiguration;
Jens Geyerd5436f52014-10-03 19:50:38 +0200245 end;
246
247 TServerTransportImpl = class( TInterfacedObject, IServerTransport)
Jens Geyera019cda2019-11-09 23:24:52 +0100248 strict private
249 FConfig : IThriftConfiguration;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100250 strict protected
Jens Geyera019cda2019-11-09 23:24:52 +0100251 function Configuration : IThriftConfiguration;
Jens Geyerd5436f52014-10-03 19:50:38 +0200252 procedure Listen; virtual; abstract;
253 procedure Close; virtual; abstract;
Jens Geyera019cda2019-11-09 23:24:52 +0100254 function Accept( const fnAccepting: TProc): ITransport; virtual; abstract;
255 public
256 constructor Create( const aConfig : IThriftConfiguration);
Jens Geyerd5436f52014-10-03 19:50:38 +0200257 end;
258
259 ITransportFactory = interface
260 ['{DD809446-000F-49E1-9BFF-E0D0DC76A9D7}']
Jens Geyer41f47af2019-11-09 23:24:52 +0100261 function GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +0200262 end;
263
Jens Geyera019cda2019-11-09 23:24:52 +0100264 TTransportFactoryImpl = class ( TInterfacedObject, ITransportFactory)
265 strict protected
Jens Geyered994552019-11-09 23:24:52 +0100266 function GetTransport( const aTransport: ITransport): ITransport; virtual;
Jens Geyerd5436f52014-10-03 19:50:38 +0200267 end;
268
Jens Geyera019cda2019-11-09 23:24:52 +0100269
270 TTcpSocketStreamImpl = class( TThriftStreamImpl)
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200271{$IFDEF OLD_SOCKETS}
Jens Geyerfad7fd32019-11-09 23:24:52 +0100272 strict private type
Jens Geyerd5436f52014-10-03 19:50:38 +0200273 TWaitForData = ( wfd_HaveData, wfd_Timeout, wfd_Error);
Jens Geyerfad7fd32019-11-09 23:24:52 +0100274 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200275 FTcpClient : TCustomIpClient;
Jens Geyerd5436f52014-10-03 19:50:38 +0200276 FTimeout : Integer;
277 function Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
278 TimeOut: Integer; var wsaError : Integer): Integer;
279 function WaitForData( TimeOut : Integer; pBuf : Pointer; DesiredBytes: Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +0200280 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200281{$ELSE}
282 FTcpClient: TSocket;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100283 strict protected const
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200284 SLEEP_TIME = 200;
285{$ENDIF}
Jens Geyerfad7fd32019-11-09 23:24:52 +0100286 strict protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200287 procedure Write( const pBuf : Pointer; offset, count: Integer); override;
288 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200289 procedure Open; override;
290 procedure Close; override;
291 procedure Flush; override;
292
293 function IsOpen: Boolean; override;
294 function ToArray: TBytes; override;
295 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200296{$IFDEF OLD_SOCKETS}
Jens Geyera019cda2019-11-09 23:24:52 +0100297 constructor Create( const aTcpClient: TCustomIpClient; const aTimeout : Integer = DEFAULT_THRIFT_TIMEOUT);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200298{$ELSE}
Jens Geyera019cda2019-11-09 23:24:52 +0100299 constructor Create( const aTcpClient: TSocket; const aTimeout : Longword = DEFAULT_THRIFT_TIMEOUT);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200300{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200301 end;
302
303 IStreamTransport = interface( ITransport )
304 ['{A8479B47-2A3E-4421-A9A0-D5A9EDCC634A}']
305 function GetInputStream: IThriftStream;
306 function GetOutputStream: IThriftStream;
307 property InputStream : IThriftStream read GetInputStream;
308 property OutputStream : IThriftStream read GetOutputStream;
309 end;
310
Jens Geyera019cda2019-11-09 23:24:52 +0100311 TStreamTransportImpl = class( TEndpointTransportBase, IStreamTransport)
Jens Geyer5a781c22025-02-04 23:35:55 +0100312 strict private
313 FInternalInputStream : IThriftStream;
314 FInternalOutputStream : IThriftStream;
315
Jens Geyerfad7fd32019-11-09 23:24:52 +0100316 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200317 function GetIsOpen: Boolean; override;
318
Jens Geyer5a781c22025-02-04 23:35:55 +0100319 function GetInputStream: IThriftStream; inline;
320 procedure SetInputStream( const stream : IThriftStream);
321
322 function GetOutputStream: IThriftStream; inline;
323 procedure SetOutputStream( const stream : IThriftStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200324
Jens Geyer41f47af2019-11-09 23:24:52 +0100325 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200326 procedure Open; override;
327 procedure Close; override;
328 procedure Flush; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200329 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
330 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyer5a781c22025-02-04 23:35:55 +0100331
332 procedure UpdateKnownMessageSize(const size : Int64); override;
Jens Geyered994552019-11-09 23:24:52 +0100333 public
Jens Geyera019cda2019-11-09 23:24:52 +0100334 constructor Create( const aInputStream, aOutputStream : IThriftStream; const aConfig : IThriftConfiguration = nil); reintroduce;
Jens Geyerd5436f52014-10-03 19:50:38 +0200335 destructor Destroy; override;
Jens Geyered994552019-11-09 23:24:52 +0100336
337 property InputStream : IThriftStream read GetInputStream;
338 property OutputStream : IThriftStream read GetOutputStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200339 end;
340
341 TBufferedStreamImpl = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100342 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200343 FStream : IThriftStream;
344 FBufSize : Integer;
Jens Geyerf726ae32021-06-04 11:17:26 +0200345 FReadBuffer : TThriftMemoryStream;
346 FWriteBuffer : TThriftMemoryStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100347 strict protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200348 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
349 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200350 procedure Open; override;
351 procedure Close; override;
352 procedure Flush; override;
353 function IsOpen: Boolean; override;
354 function ToArray: TBytes; override;
Jens Geyer5a781c22025-02-04 23:35:55 +0100355 function CanSeek : Boolean; override;
Jens Geyera019cda2019-11-09 23:24:52 +0100356 function Size : Int64; override;
357 function Position : Int64; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200358 public
Jens Geyered994552019-11-09 23:24:52 +0100359 constructor Create( const aStream: IThriftStream; const aBufSize : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200360 destructor Destroy; override;
361 end;
362
363 TServerSocketImpl = class( TServerTransportImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100364 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200365{$IFDEF OLD_SOCKETS}
366 FServer : TTcpServer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200367 FPort : Integer;
368 FClientTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200369{$ELSE}
370 FServer: TServerSocket;
371{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200372 FUseBufferedSocket : Boolean;
373 FOwnsServer : Boolean;
Jens Geyer41f47af2019-11-09 23:24:52 +0100374
Jens Geyerfad7fd32019-11-09 23:24:52 +0100375 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200376 function Accept( const fnAccepting: TProc) : ITransport; override;
Jens Geyer41f47af2019-11-09 23:24:52 +0100377
Jens Geyerd5436f52014-10-03 19:50:38 +0200378 public
Jens Geyera019cda2019-11-09 23:24:52 +0100379 {$IFDEF OLD_SOCKETS}
380 constructor Create( const aServer: TTcpServer; const aClientTimeout : Integer = DEFAULT_THRIFT_TIMEOUT; const aConfig : IThriftConfiguration = nil); overload;
381 constructor Create( const aPort: Integer; const aClientTimeout: Integer = DEFAULT_THRIFT_TIMEOUT; aUseBufferedSockets: Boolean = FALSE; const aConfig : IThriftConfiguration = nil); overload;
382 {$ELSE}
383 constructor Create( const aServer: TServerSocket; const aClientTimeout: Longword = DEFAULT_THRIFT_TIMEOUT; const aConfig : IThriftConfiguration = nil); overload;
384 constructor Create( const aPort: Integer; const aClientTimeout: Longword = DEFAULT_THRIFT_TIMEOUT; aUseBufferedSockets: Boolean = FALSE; const aConfig : IThriftConfiguration = nil); overload;
385 {$ENDIF}
386
Jens Geyerd5436f52014-10-03 19:50:38 +0200387 destructor Destroy; override;
388 procedure Listen; override;
389 procedure Close; override;
390 end;
391
Jens Geyera019cda2019-11-09 23:24:52 +0100392 TBufferedTransportImpl = class( TLayeredTransportBase<IStreamTransport>)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100393 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200394 FInputBuffer : IThriftStream;
395 FOutputBuffer : IThriftStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200396 FBufSize : Integer;
397
398 procedure InitBuffers;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100399 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200400 function GetIsOpen: Boolean; override;
401 procedure Flush; override;
402 public
Jens Geyered994552019-11-09 23:24:52 +0100403 type
404 TFactory = class( TTransportFactoryImpl )
405 public
406 function GetTransport( const aTransport: ITransport): ITransport; override;
407 end;
408
409 constructor Create( const aTransport : IStreamTransport; const aBufSize: Integer = 1024);
Jens Geyerd5436f52014-10-03 19:50:38 +0200410 procedure Open(); override;
411 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200412 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
413 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyera019cda2019-11-09 23:24:52 +0100414 procedure CheckReadBytesAvailable( const value : Int64); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200415 property IsOpen: Boolean read GetIsOpen;
416 end;
417
418 TSocketImpl = class(TStreamTransportImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100419 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200420{$IFDEF OLD_SOCKETS}
421 FClient : TCustomIpClient;
422{$ELSE}
423 FClient: TSocket;
424{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200425 FOwnsClient : Boolean;
426 FHost : string;
427 FPort : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200428{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200429 FTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200430{$ELSE}
431 FTimeout : Longword;
432{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200433
434 procedure InitSocket;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100435 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200436 function GetIsOpen: Boolean; override;
437 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200438{$IFDEF OLD_SOCKETS}
Jens Geyera019cda2019-11-09 23:24:52 +0100439 constructor Create( const aClient : TCustomIpClient; const aOwnsClient : Boolean; const aTimeout: Integer = DEFAULT_THRIFT_TIMEOUT; const aConfig : IThriftConfiguration = nil); overload;
440 constructor Create( const aHost: string; const aPort: Integer; const aTimeout: Integer = DEFAULT_THRIFT_TIMEOUT; const aConfig : IThriftConfiguration = nil); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200441{$ELSE}
Jens Geyera019cda2019-11-09 23:24:52 +0100442 constructor Create(const aClient: TSocket; const aOwnsClient: Boolean; const aConfig : IThriftConfiguration = nil); overload;
443 constructor Create( const aHost: string; const aPort: Integer; const aTimeout: Longword = DEFAULT_THRIFT_TIMEOUT; const aConfig : IThriftConfiguration = nil); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200444{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200445 destructor Destroy; override;
Jens Geyera019cda2019-11-09 23:24:52 +0100446
447 procedure Open; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200448 procedure Close; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200449{$IFDEF OLD_SOCKETS}
450 property TcpClient: TCustomIpClient read FClient;
451{$ELSE}
452 property TcpClient: TSocket read FClient;
453{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200454 property Host : string read FHost;
455 property Port: Integer read FPort;
456 end;
457
Jens Geyera019cda2019-11-09 23:24:52 +0100458 TFramedTransportImpl = class( TLayeredTransportBase<ITransport>)
Jens Geyer2646bd62019-11-09 23:24:52 +0100459 strict protected type
460 TFramedHeader = Int32;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100461 strict protected
Jens Geyerf726ae32021-06-04 11:17:26 +0200462 FWriteBuffer : TThriftMemoryStream;
463 FReadBuffer : TThriftMemoryStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200464
465 procedure InitWriteBuffer;
466 procedure ReadFrame;
Jens Geyerd5436f52014-10-03 19:50:38 +0200467
468 procedure Open(); override;
Jens Geyera019cda2019-11-09 23:24:52 +0100469 function GetIsOpen: Boolean; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200470
471 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200472 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
473 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyera019cda2019-11-09 23:24:52 +0100474 procedure CheckReadBytesAvailable( const value : Int64); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200475 procedure Flush; override;
Jens Geyera019cda2019-11-09 23:24:52 +0100476
Jens Geyered994552019-11-09 23:24:52 +0100477 public
478 type
479 TFactory = class( TTransportFactoryImpl )
480 public
481 function GetTransport( const aTransport: ITransport): ITransport; override;
482 end;
483
484 constructor Create( const aTransport: ITransport); overload;
485 destructor Destroy; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200486 end;
487
Jens Geyerd5436f52014-10-03 19:50:38 +0200488
489const
fcprete28113f42025-06-10 02:54:38 +0200490 // From https://learn.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp-
491 // > TLS 1.3 is supported starting in Windows 11 and Windows Server 2022.
492 // > Enabling TLS 1.3 on earlier versions of Windows is not a safe system configuration.
493 DEFAULT_THRIFT_SECUREPROTOCOLS = [
494 TSecureProtocol.TLS_1_2
495 //TSecureProtocol.TLS_1_3 -- not supported on Win10 (see comment)
496 ];
Jens Geyer47f63172019-06-06 22:42:58 +0200497
Jens Geyerd5436f52014-10-03 19:50:38 +0200498implementation
499
Jens Geyered994552019-11-09 23:24:52 +0100500
Jens Geyera019cda2019-11-09 23:24:52 +0100501{ TTransportBase }
Jens Geyer41f47af2019-11-09 23:24:52 +0100502
Jens Geyera019cda2019-11-09 23:24:52 +0100503procedure TTransportBase.Flush;
Jens Geyerd5436f52014-10-03 19:50:38 +0200504begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200505 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200506end;
507
Jens Geyera019cda2019-11-09 23:24:52 +0100508function TTransportBase.Peek: Boolean;
Jens Geyerd5436f52014-10-03 19:50:38 +0200509begin
510 Result := IsOpen;
511end;
512
Jens Geyera019cda2019-11-09 23:24:52 +0100513function TTransportBase.Read(var buf: TBytes; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200514begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200515 if Length(buf) > 0
516 then result := Read( @buf[0], Length(buf), off, len)
517 else result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200518end;
519
Jens Geyera019cda2019-11-09 23:24:52 +0100520function TTransportBase.ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200521begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200522 if Length(buf) > 0
523 then result := ReadAll( @buf[0], Length(buf), off, len)
524 else result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200525end;
526
Jens Geyera019cda2019-11-09 23:24:52 +0100527function TTransportBase.ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200528var ret : Integer;
529begin
530 result := 0;
531 while result < len do begin
532 ret := Read( pBuf, buflen, off + result, len - result);
533 if ret > 0
534 then Inc( result, ret)
535 else raise TTransportExceptionNotOpen.Create( 'Cannot read, Remote side has closed' );
536 end;
537end;
538
Jens Geyera019cda2019-11-09 23:24:52 +0100539procedure TTransportBase.Write( const buf: TBytes);
Jens Geyered994552019-11-09 23:24:52 +0100540begin
541 if Length(buf) > 0
542 then Write( @buf[0], 0, Length(buf));
543end;
544
Jens Geyera019cda2019-11-09 23:24:52 +0100545procedure TTransportBase.Write( const buf: TBytes; off: Integer; len: Integer);
Jens Geyered994552019-11-09 23:24:52 +0100546begin
547 if Length(buf) > 0
548 then Write( @buf[0], off, len);
549end;
550
Jens Geyera019cda2019-11-09 23:24:52 +0100551procedure TTransportBase.Write( const pBuf : Pointer; len : Integer);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200552begin
553 Self.Write( pBuf, 0, len);
Jens Geyerd5436f52014-10-03 19:50:38 +0200554end;
555
Jens Geyered994552019-11-09 23:24:52 +0100556
Jens Geyera019cda2019-11-09 23:24:52 +0100557{ TEndpointTransportBase }
558
559constructor TEndpointTransportBase.Create( const aConfig : IThriftConfiguration);
Jens Geyer41f47af2019-11-09 23:24:52 +0100560begin
Jens Geyera019cda2019-11-09 23:24:52 +0100561 inherited Create;
562
563 if aConfig <> nil
564 then FConfiguration := aConfig
565 else FConfiguration := TThriftConfigurationImpl.Create;
566
Jens Geyer5a781c22025-02-04 23:35:55 +0100567 ResetMessageSizeAndConsumedBytes;
Jens Geyer41f47af2019-11-09 23:24:52 +0100568end;
569
570
Jens Geyera019cda2019-11-09 23:24:52 +0100571function TEndpointTransportBase.Configuration : IThriftConfiguration;
Jens Geyer41f47af2019-11-09 23:24:52 +0100572begin
Jens Geyera019cda2019-11-09 23:24:52 +0100573 result := FConfiguration;
Jens Geyer41f47af2019-11-09 23:24:52 +0100574end;
575
576
Jens Geyera019cda2019-11-09 23:24:52 +0100577function TEndpointTransportBase.MaxMessageSize : Integer;
578begin
579 ASSERT( Configuration <> nil);
580 result := Configuration.MaxMessageSize;
581end;
582
583
Jens Geyer5a781c22025-02-04 23:35:55 +0100584procedure TEndpointTransportBase.ResetMessageSizeAndConsumedBytes( const newSize : Int64);
Jens Geyera019cda2019-11-09 23:24:52 +0100585// Resets RemainingMessageSize to the configured maximum
586begin
587 // full reset
588 if newSize < 0 then begin
589 FKnownMessageSize := MaxMessageSize;
590 FRemainingMessageSize := MaxMessageSize;
591 Exit;
592 end;
593
594 // update only: message size can shrink, but not grow
595 ASSERT( KnownMessageSize <= MaxMessageSize);
596 if newSize > KnownMessageSize
Jens Geyerb0123182020-02-12 12:16:19 +0100597 then raise TTransportExceptionEndOfFile.Create('MaxMessageSize reached');
Jens Geyera019cda2019-11-09 23:24:52 +0100598
599 FKnownMessageSize := newSize;
600 FRemainingMessageSize := newSize;
601end;
602
603
604procedure TEndpointTransportBase.UpdateKnownMessageSize( const size : Int64);
Jens Geyer5a781c22025-02-04 23:35:55 +0100605// Updates RemainingMessageSize to reflect the known real message size (e.g. framed transport).
Jens Geyera019cda2019-11-09 23:24:52 +0100606// Will throw if we already consumed too many bytes.
607var consumed : Int64;
608begin
609 consumed := KnownMessageSize - RemainingMessageSize;
Jens Geyer5a781c22025-02-04 23:35:55 +0100610 ResetMessageSizeAndConsumedBytes(size);
Jens Geyera019cda2019-11-09 23:24:52 +0100611 CountConsumedMessageBytes(consumed);
612end;
613
614
615procedure TEndpointTransportBase.CheckReadBytesAvailable( const numBytes : Int64);
616// Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data
617begin
Jens Geyer73f5bd42022-09-03 14:19:31 +0200618 if (RemainingMessageSize < numBytes) or (numBytes < 0)
Jens Geyera019cda2019-11-09 23:24:52 +0100619 then raise TTransportExceptionEndOfFile.Create('MaxMessageSize reached');
620end;
621
622
623procedure TEndpointTransportBase.CountConsumedMessageBytes( const numBytes : Int64);
624// Consumes numBytes from the RemainingMessageSize.
625begin
Jens Geyer73f5bd42022-09-03 14:19:31 +0200626 if (RemainingMessageSize >= numBytes) and (numBytes >= 0)
Jens Geyera019cda2019-11-09 23:24:52 +0100627 then Dec( FRemainingMessageSize, numBytes)
628 else begin
629 FRemainingMessageSize := 0;
630 raise TTransportExceptionEndOfFile.Create('MaxMessageSize reached');
631 end;
632end;
633
634{ TLayeredTransportBase }
635
636constructor TLayeredTransportBase<T>.Create( const aTransport: T);
637begin
638 inherited Create;
639 FTransport := aTransport;
640end;
641
642function TLayeredTransportBase<T>.GetUnderlyingTransport: ITransport;
643begin
644 result := InnerTransport;
645end;
646
647function TLayeredTransportBase<T>.Configuration : IThriftConfiguration;
648begin
649 result := InnerTransport.Configuration;
650end;
651
652procedure TLayeredTransportBase<T>.UpdateKnownMessageSize( const size : Int64);
653begin
654 InnerTransport.UpdateKnownMessageSize( size);
655end;
656
657
658function TLayeredTransportBase<T>.MaxMessageSize : Integer;
659begin
660 result := InnerTransport.MaxMessageSize;
661end;
662
663
Jens Geyer5a781c22025-02-04 23:35:55 +0100664procedure TLayeredTransportBase<T>.ResetMessageSizeAndConsumedBytes( const knownSize : Int64 = -1);
Jens Geyera019cda2019-11-09 23:24:52 +0100665begin
Jens Geyer5a781c22025-02-04 23:35:55 +0100666 InnerTransport.ResetMessageSizeAndConsumedBytes( knownSize);
Jens Geyera019cda2019-11-09 23:24:52 +0100667end;
668
669
670procedure TLayeredTransportBase<T>.CheckReadBytesAvailable( const numBytes : Int64);
671begin
672 InnerTransport.CheckReadBytesAvailable( numBytes);
673end;
674
675
676
Jens Geyerd5436f52014-10-03 19:50:38 +0200677{ TTransportException }
678
Jens Geyere0e32402016-04-20 21:50:48 +0200679constructor TTransportException.HiddenCreate(const Msg: string);
680begin
681 inherited Create(Msg);
682end;
683
Jens Geyered994552019-11-09 23:24:52 +0100684class function TTransportException.Create(aType: TExceptionType): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200685begin
686 //no inherited;
Jens Geyere0e32402016-04-20 21:50:48 +0200687{$WARN SYMBOL_DEPRECATED OFF}
Jens Geyered994552019-11-09 23:24:52 +0100688 Result := Create(aType, '')
Jens Geyere0e32402016-04-20 21:50:48 +0200689{$WARN SYMBOL_DEPRECATED DEFAULT}
Jens Geyerd5436f52014-10-03 19:50:38 +0200690end;
691
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100692class function TTransportException.Create(aType: TExceptionType; const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200693begin
Jens Geyered994552019-11-09 23:24:52 +0100694 case aType of
Jens Geyere0e32402016-04-20 21:50:48 +0200695 TExceptionType.NotOpen: Result := TTransportExceptionNotOpen.Create(msg);
696 TExceptionType.AlreadyOpen: Result := TTransportExceptionAlreadyOpen.Create(msg);
697 TExceptionType.TimedOut: Result := TTransportExceptionTimedOut.Create(msg);
698 TExceptionType.EndOfFile: Result := TTransportExceptionEndOfFile.Create(msg);
699 TExceptionType.BadArgs: Result := TTransportExceptionBadArgs.Create(msg);
700 TExceptionType.Interrupted: Result := TTransportExceptionInterrupted.Create(msg);
701 else
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100702 ASSERT( TExceptionType.Unknown = aType);
Jens Geyere0e32402016-04-20 21:50:48 +0200703 Result := TTransportExceptionUnknown.Create(msg);
704 end;
Jens Geyerd5436f52014-10-03 19:50:38 +0200705end;
706
Jens Geyere0e32402016-04-20 21:50:48 +0200707class function TTransportException.Create(const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200708begin
Jens Geyere0e32402016-04-20 21:50:48 +0200709 Result := TTransportExceptionUnknown.Create(Msg);
710end;
711
712{ TTransportExceptionSpecialized }
713
714constructor TTransportExceptionSpecialized.Create(const Msg: string);
715begin
716 inherited HiddenCreate(Msg);
Jens Geyerd5436f52014-10-03 19:50:38 +0200717end;
718
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100719{ specialized TTransportExceptions }
720
721class function TTransportExceptionUnknown.GetType: TTransportException.TExceptionType;
722begin
723 result := TExceptionType.Unknown;
724end;
725
726class function TTransportExceptionNotOpen.GetType: TTransportException.TExceptionType;
727begin
728 result := TExceptionType.NotOpen;
729end;
730
731class function TTransportExceptionAlreadyOpen.GetType: TTransportException.TExceptionType;
732begin
733 result := TExceptionType.AlreadyOpen;
734end;
735
736class function TTransportExceptionTimedOut.GetType: TTransportException.TExceptionType;
737begin
738 result := TExceptionType.TimedOut;
739end;
740
741class function TTransportExceptionEndOfFile.GetType: TTransportException.TExceptionType;
742begin
743 result := TExceptionType.EndOfFile;
744end;
745
746class function TTransportExceptionBadArgs.GetType: TTransportException.TExceptionType;
747begin
748 result := TExceptionType.BadArgs;
749end;
750
751class function TTransportExceptionInterrupted.GetType: TTransportException.TExceptionType;
752begin
753 result := TExceptionType.Interrupted;
754end;
755
Jens Geyer2646bd62019-11-09 23:24:52 +0100756class function TTransportExceptionCorruptedData.GetType: TTransportException.TExceptionType;
757begin
758 result := TExceptionType.CorruptedData;
759end;
760
Jens Geyerd5436f52014-10-03 19:50:38 +0200761{ TTransportFactoryImpl }
762
Jens Geyered994552019-11-09 23:24:52 +0100763function TTransportFactoryImpl.GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +0200764begin
Jens Geyered994552019-11-09 23:24:52 +0100765 Result := aTransport;
Jens Geyerd5436f52014-10-03 19:50:38 +0200766end;
767
Jens Geyera019cda2019-11-09 23:24:52 +0100768
769{ TServerTransportImpl }
770
771constructor TServerTransportImpl.Create( const aConfig : IThriftConfiguration);
772begin
773 inherited Create;
774 if aConfig <> nil
775 then FConfig := aConfig
776 else FConfig := TThriftConfigurationImpl.Create;
777end;
778
779function TServerTransportImpl.Configuration : IThriftConfiguration;
780begin
781 result := FConfig;
782end;
783
Jens Geyerd5436f52014-10-03 19:50:38 +0200784{ TServerSocket }
785
Jens Geyer23d67462015-12-19 11:44:57 +0100786{$IFDEF OLD_SOCKETS}
Jens Geyera019cda2019-11-09 23:24:52 +0100787constructor TServerSocketImpl.Create( const aServer: TTcpServer; const aClientTimeout : Integer; const aConfig : IThriftConfiguration);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200788{$ELSE}
Jens Geyera019cda2019-11-09 23:24:52 +0100789constructor TServerSocketImpl.Create( const aServer: TServerSocket; const aClientTimeout: Longword; const aConfig : IThriftConfiguration);
Jens Geyered994552019-11-09 23:24:52 +0100790{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200791begin
Jens Geyera019cda2019-11-09 23:24:52 +0100792 inherited Create( aConfig);
Jens Geyered994552019-11-09 23:24:52 +0100793 FServer := aServer;
Jens Geyera019cda2019-11-09 23:24:52 +0100794
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200795
796{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100797 FClientTimeout := aClientTimeout;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200798{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +0100799 FServer.RecvTimeout := aClientTimeout;
800 FServer.SendTimeout := aClientTimeout;
801{$ENDIF}
802end;
803
804
805{$IFDEF OLD_SOCKETS}
Jens Geyera019cda2019-11-09 23:24:52 +0100806constructor TServerSocketImpl.Create( const aPort: Integer; const aClientTimeout: Integer; aUseBufferedSockets: Boolean; const aConfig : IThriftConfiguration);
Jens Geyered994552019-11-09 23:24:52 +0100807{$ELSE}
Jens Geyera019cda2019-11-09 23:24:52 +0100808constructor TServerSocketImpl.Create( const aPort: Integer; const aClientTimeout: Longword; aUseBufferedSockets: Boolean; const aConfig : IThriftConfiguration);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200809{$ENDIF}
810begin
Jens Geyera019cda2019-11-09 23:24:52 +0100811 inherited Create( aConfig);
Jens Geyer41f47af2019-11-09 23:24:52 +0100812
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200813{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100814 FPort := aPort;
815 FClientTimeout := aClientTimeout;
816
817 FOwnsServer := True;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200818 FServer := TTcpServer.Create( nil );
Jens Geyerd5436f52014-10-03 19:50:38 +0200819 FServer.BlockMode := bmBlocking;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200820 {$IF CompilerVersion >= 21.0}
Jens Geyerd5436f52014-10-03 19:50:38 +0200821 FServer.LocalPort := AnsiString( IntToStr( FPort));
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200822 {$ELSE}
Jens Geyerd5436f52014-10-03 19:50:38 +0200823 FServer.LocalPort := IntToStr( FPort);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200824 {$IFEND}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200825{$ELSE}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200826 FOwnsServer := True;
Jens Geyered994552019-11-09 23:24:52 +0100827 FServer := TServerSocket.Create(aPort, aClientTimeout, aClientTimeout);
828{$ENDIF}
829
830 FUseBufferedSocket := aUseBufferedSockets;
Jens Geyerd5436f52014-10-03 19:50:38 +0200831end;
832
833destructor TServerSocketImpl.Destroy;
834begin
835 if FOwnsServer then begin
836 FServer.Free;
837 FServer := nil;
838 end;
839 inherited;
840end;
841
842function TServerSocketImpl.Accept( const fnAccepting: TProc): ITransport;
843var
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200844{$IFDEF OLD_SOCKETS}
845 client : TCustomIpClient;
846{$ELSE}
847 client: TSocket;
848{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200849 trans : IStreamTransport;
850begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100851 if FServer = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200852 raise TTransportExceptionNotOpen.Create('No underlying server socket.');
Jens Geyerd5436f52014-10-03 19:50:38 +0200853 end;
854
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200855{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200856 client := nil;
857 try
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200858 client := TCustomIpClient.Create(nil);
Jens Geyerd5436f52014-10-03 19:50:38 +0200859
860 if Assigned(fnAccepting)
861 then fnAccepting();
862
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100863 if not FServer.Accept( client) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200864 client.Free;
865 Result := nil;
866 Exit;
867 end;
868
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100869 if client = nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200870 Result := nil;
871 Exit;
872 end;
873
Jens Geyera019cda2019-11-09 23:24:52 +0100874 trans := TSocketImpl.Create( client, TRUE, FClientTimeout, Configuration);
Jens Geyerd5436f52014-10-03 19:50:38 +0200875 client := nil; // trans owns it now
876
877 if FUseBufferedSocket
878 then result := TBufferedTransportImpl.Create( trans)
879 else result := trans;
880
881 except
882 on E: Exception do begin
883 client.Free;
Jens Geyere0e32402016-04-20 21:50:48 +0200884 raise TTransportExceptionUnknown.Create(E.ToString);
Jens Geyerd5436f52014-10-03 19:50:38 +0200885 end;
886 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200887{$ELSE}
888 if Assigned(fnAccepting) then
889 fnAccepting();
890
891 client := FServer.Accept;
892 try
Jens Geyera019cda2019-11-09 23:24:52 +0100893 trans := TSocketImpl.Create(client, TRUE, Configuration);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200894 client := nil;
895
896 if FUseBufferedSocket then
897 Result := TBufferedTransportImpl.Create(trans)
898 else
899 Result := trans;
900 except
901 client.Free;
902 raise;
903 end;
904{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200905end;
906
907procedure TServerSocketImpl.Listen;
908begin
909 if FServer <> nil then
910 begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200911{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200912 try
913 FServer.Active := True;
914 except
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200915 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200916 do raise TTransportExceptionUnknown.Create('Could not accept on listening socket: ' + E.Message);
Jens Geyerd5436f52014-10-03 19:50:38 +0200917 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200918{$ELSE}
919 FServer.Listen;
920{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200921 end;
922end;
923
924procedure TServerSocketImpl.Close;
925begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200926 if FServer <> nil then
927{$IFDEF OLD_SOCKETS}
928 try
929 FServer.Active := False;
930 except
931 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200932 do raise TTransportExceptionUnknown.Create('Error on closing socket : ' + E.Message);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200933 end;
934{$ELSE}
935 FServer.Close;
936{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200937end;
938
939{ TSocket }
940
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200941{$IFDEF OLD_SOCKETS}
Jens Geyera019cda2019-11-09 23:24:52 +0100942constructor TSocketImpl.Create( const aClient : TCustomIpClient; const aOwnsClient : Boolean; const aTimeout: Integer; const aConfig : IThriftConfiguration);
Jens Geyered994552019-11-09 23:24:52 +0100943{$ELSE}
Jens Geyera019cda2019-11-09 23:24:52 +0100944constructor TSocketImpl.Create(const aClient: TSocket; const aOwnsClient: Boolean; const aConfig : IThriftConfiguration);
Jens Geyered994552019-11-09 23:24:52 +0100945{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200946var stream : IThriftStream;
947begin
Jens Geyered994552019-11-09 23:24:52 +0100948 FClient := aClient;
Jens Geyerd5436f52014-10-03 19:50:38 +0200949 FOwnsClient := aOwnsClient;
Jens Geyered994552019-11-09 23:24:52 +0100950
951{$IFDEF OLD_SOCKETS}
952 FTimeout := aTimeout;
953{$ELSE}
954 FTimeout := aClient.RecvTimeout;
955{$ENDIF}
956
Jens Geyerd5436f52014-10-03 19:50:38 +0200957 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
Jens Geyera019cda2019-11-09 23:24:52 +0100958 inherited Create( stream, stream, aConfig);
Jens Geyerd5436f52014-10-03 19:50:38 +0200959end;
960
Jens Geyera019cda2019-11-09 23:24:52 +0100961
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200962{$IFDEF OLD_SOCKETS}
Jens Geyera019cda2019-11-09 23:24:52 +0100963constructor TSocketImpl.Create(const aHost: string; const aPort, aTimeout: Integer; const aConfig : IThriftConfiguration);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200964{$ELSE}
Jens Geyera019cda2019-11-09 23:24:52 +0100965constructor TSocketImpl.Create(const aHost: string; const aPort : Integer; const aTimeout: Longword; const aConfig : IThriftConfiguration);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200966{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200967begin
Jens Geyera019cda2019-11-09 23:24:52 +0100968 inherited Create(nil,nil, aConfig);
Jens Geyered994552019-11-09 23:24:52 +0100969 FHost := aHost;
970 FPort := aPort;
971 FTimeout := aTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200972 InitSocket;
973end;
974
975destructor TSocketImpl.Destroy;
976begin
977 if FOwnsClient
978 then FreeAndNil( FClient);
979 inherited;
980end;
981
982procedure TSocketImpl.Close;
983begin
984 inherited Close;
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200985
Jens Geyer5a781c22025-02-04 23:35:55 +0100986 SetInputStream( nil);
987 SetOutputStream( nil);
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200988
Jens Geyerd5436f52014-10-03 19:50:38 +0200989 if FOwnsClient
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200990 then FreeAndNil( FClient)
991 else FClient := nil;
Jens Geyerd5436f52014-10-03 19:50:38 +0200992end;
993
994function TSocketImpl.GetIsOpen: Boolean;
995begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200996{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200997 Result := (FClient <> nil) and FClient.Connected;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200998{$ELSE}
999 Result := (FClient <> nil) and FClient.IsOpen
1000{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001001end;
1002
1003procedure TSocketImpl.InitSocket;
1004var
1005 stream : IThriftStream;
1006begin
1007 if FOwnsClient
1008 then FreeAndNil( FClient)
1009 else FClient := nil;
1010
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001011{$IFDEF OLD_SOCKETS}
1012 FClient := TTcpClient.Create( nil);
1013{$ELSE}
1014 FClient := TSocket.Create(FHost, FPort);
1015{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001016 FOwnsClient := True;
1017
1018 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
Jens Geyer5a781c22025-02-04 23:35:55 +01001019 SetInputStream( stream);
1020 SetOutputStream( stream);
Jens Geyerd5436f52014-10-03 19:50:38 +02001021end;
1022
1023procedure TSocketImpl.Open;
1024begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001025 if IsOpen then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001026 raise TTransportExceptionAlreadyOpen.Create('Socket already connected');
Jens Geyerd5436f52014-10-03 19:50:38 +02001027 end;
1028
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001029 if FHost = '' then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001030 raise TTransportExceptionNotOpen.Create('Cannot open null host');
Jens Geyerd5436f52014-10-03 19:50:38 +02001031 end;
1032
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001033 if Port <= 0 then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001034 raise TTransportExceptionNotOpen.Create('Cannot open without port');
Jens Geyerd5436f52014-10-03 19:50:38 +02001035 end;
1036
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001037 if FClient = nil
1038 then InitSocket;
Jens Geyerd5436f52014-10-03 19:50:38 +02001039
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001040{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001041 FClient.RemoteHost := TSocketHost( Host);
1042 FClient.RemotePort := TSocketPort( IntToStr( Port));
1043 FClient.Connect;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001044{$ELSE}
1045 FClient.Open;
1046{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001047
Jens Geyer5a781c22025-02-04 23:35:55 +01001048 SetInputStream( TTcpSocketStreamImpl.Create( FClient, FTimeout));
1049 SetOutputStream( InputStream); // same
Jens Geyerd5436f52014-10-03 19:50:38 +02001050end;
1051
1052{ TBufferedStream }
1053
1054procedure TBufferedStreamImpl.Close;
1055begin
1056 Flush;
1057 FStream := nil;
1058
1059 FReadBuffer.Free;
1060 FReadBuffer := nil;
1061
1062 FWriteBuffer.Free;
1063 FWriteBuffer := nil;
1064end;
1065
Jens Geyered994552019-11-09 23:24:52 +01001066constructor TBufferedStreamImpl.Create( const aStream: IThriftStream; const aBufSize : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001067begin
1068 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +01001069 FStream := aStream;
1070 FBufSize := aBufSize;
Jens Geyerf726ae32021-06-04 11:17:26 +02001071 FReadBuffer := TThriftMemoryStream.Create(FBufSize);
1072 FWriteBuffer := TThriftMemoryStream.Create(FBufSize);
Jens Geyerd5436f52014-10-03 19:50:38 +02001073end;
1074
1075destructor TBufferedStreamImpl.Destroy;
1076begin
1077 Close;
1078 inherited;
1079end;
1080
1081procedure TBufferedStreamImpl.Flush;
1082var
1083 buf : TBytes;
1084 len : Integer;
1085begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001086 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001087 len := FWriteBuffer.Size;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001088 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001089 SetLength( buf, len );
1090 FWriteBuffer.Position := 0;
1091 FWriteBuffer.Read( Pointer(@buf[0])^, len );
1092 FStream.Write( buf, 0, len );
1093 end;
1094 FWriteBuffer.Clear;
1095 end;
1096end;
1097
1098function TBufferedStreamImpl.IsOpen: Boolean;
1099begin
1100 Result := (FWriteBuffer <> nil)
1101 and (FReadBuffer <> nil)
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001102 and (FStream <> nil)
1103 and FStream.IsOpen;
Jens Geyerd5436f52014-10-03 19:50:38 +02001104end;
1105
1106procedure TBufferedStreamImpl.Open;
1107begin
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001108 FStream.Open;
Jens Geyerd5436f52014-10-03 19:50:38 +02001109end;
1110
Jens Geyer17c3ad92017-09-05 20:31:27 +02001111function TBufferedStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001112var
1113 nRead : Integer;
1114 tempbuf : TBytes;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001115 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001116begin
1117 inherited;
1118 Result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001119
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001120 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001121 while count > 0 do begin
1122
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001123 if FReadBuffer.Position >= FReadBuffer.Size then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001124 FReadBuffer.Clear;
1125 SetLength( tempbuf, FBufSize);
1126 nRead := FStream.Read( tempbuf, 0, FBufSize );
1127 if nRead = 0 then Break; // avoid infinite loop
1128
1129 FReadBuffer.WriteBuffer( Pointer(@tempbuf[0])^, nRead );
1130 FReadBuffer.Position := 0;
1131 end;
1132
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001133 if FReadBuffer.Position < FReadBuffer.Size then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001134 nRead := Min( FReadBuffer.Size - FReadBuffer.Position, count);
1135 pTmp := pBuf;
1136 Inc( pTmp, offset);
1137 Inc( Result, FReadBuffer.Read( pTmp^, nRead));
Jens Geyerd5436f52014-10-03 19:50:38 +02001138 Dec( count, nRead);
1139 Inc( offset, nRead);
1140 end;
1141 end;
1142 end;
1143end;
1144
Jens Geyered994552019-11-09 23:24:52 +01001145
Jens Geyerd5436f52014-10-03 19:50:38 +02001146function TBufferedStreamImpl.ToArray: TBytes;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001147var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001148begin
Jens Geyera019cda2019-11-09 23:24:52 +01001149 if IsOpen
1150 then len := FReadBuffer.Size
1151 else len := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +02001152
1153 SetLength( Result, len);
1154
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001155 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001156 FReadBuffer.Position := 0;
1157 FReadBuffer.Read( Pointer(@Result[0])^, len );
1158 end;
1159end;
1160
Jens Geyer17c3ad92017-09-05 20:31:27 +02001161procedure TBufferedStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001162var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001163begin
1164 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001165 if count > 0 then begin
1166 if IsOpen then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001167 pTmp := pBuf;
1168 Inc( pTmp, offset);
1169 FWriteBuffer.Write( pTmp^, count );
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001170 if FWriteBuffer.Size > FBufSize then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001171 Flush;
1172 end;
1173 end;
1174 end;
1175end;
1176
Jens Geyera019cda2019-11-09 23:24:52 +01001177
Jens Geyer5a781c22025-02-04 23:35:55 +01001178function TBufferedStreamImpl.CanSeek : Boolean;
1179begin
1180 result := TRUE;
1181end;
1182
1183
Jens Geyera019cda2019-11-09 23:24:52 +01001184function TBufferedStreamImpl.Size : Int64;
1185begin
1186 result := FReadBuffer.Size;
1187end;
1188
1189
1190function TBufferedStreamImpl.Position : Int64;
1191begin
1192 result := FReadBuffer.Position;
1193end;
1194
1195
Jens Geyerd5436f52014-10-03 19:50:38 +02001196{ TStreamTransportImpl }
1197
Jens Geyera019cda2019-11-09 23:24:52 +01001198constructor TStreamTransportImpl.Create( const aInputStream, aOutputStream : IThriftStream; const aConfig : IThriftConfiguration);
Jens Geyerd5436f52014-10-03 19:50:38 +02001199begin
Jens Geyera019cda2019-11-09 23:24:52 +01001200 inherited Create( aConfig);
Jens Geyer5a781c22025-02-04 23:35:55 +01001201 SetInputStream( aInputStream);
1202 SetOutputStream( aOutputStream);
Jens Geyerd5436f52014-10-03 19:50:38 +02001203end;
1204
1205destructor TStreamTransportImpl.Destroy;
1206begin
Jens Geyer5a781c22025-02-04 23:35:55 +01001207 SetInputStream( nil);
1208 SetInputStream( nil);
Jens Geyerd5436f52014-10-03 19:50:38 +02001209 inherited;
1210end;
1211
Jens Geyer20e727e2018-06-22 22:39:57 +02001212procedure TStreamTransportImpl.Close;
1213begin
Jens Geyer5a781c22025-02-04 23:35:55 +01001214 SetInputStream( nil);
1215 SetInputStream( nil);
Jens Geyer20e727e2018-06-22 22:39:57 +02001216end;
1217
Jens Geyerd5436f52014-10-03 19:50:38 +02001218procedure TStreamTransportImpl.Flush;
1219begin
Jens Geyer5a781c22025-02-04 23:35:55 +01001220 if OutputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001221 raise TTransportExceptionNotOpen.Create('Cannot flush null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001222 end;
1223
Jens Geyer5a781c22025-02-04 23:35:55 +01001224 OutputStream.Flush;
Jens Geyerd5436f52014-10-03 19:50:38 +02001225end;
1226
1227function TStreamTransportImpl.GetInputStream: IThriftStream;
1228begin
Jens Geyer5a781c22025-02-04 23:35:55 +01001229 Result := FInternalInputStream;
1230end;
1231
1232procedure TStreamTransportImpl.SetInputStream( const stream : IThriftStream);
1233begin
1234 FInternalInputStream := stream;
1235 ResetMessageSizeAndConsumedBytes(-1); // full reset to configured maximum
1236 UpdateKnownMessageSize( -1); // adjust to real stream size
1237end;
1238
1239function TStreamTransportImpl.GetOutputStream: IThriftStream;
1240begin
1241 Result := FInternalOutputStream;
1242end;
1243
1244procedure TStreamTransportImpl.SetOutputStream( const stream : IThriftStream);
1245begin
1246 FInternalOutputStream := stream;
Jens Geyerd5436f52014-10-03 19:50:38 +02001247end;
1248
1249function TStreamTransportImpl.GetIsOpen: Boolean;
1250begin
1251 Result := True;
1252end;
1253
Jens Geyerd5436f52014-10-03 19:50:38 +02001254procedure TStreamTransportImpl.Open;
1255begin
Jens Geyer2646bd62019-11-09 23:24:52 +01001256 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +02001257end;
1258
Jens Geyer17c3ad92017-09-05 20:31:27 +02001259function TStreamTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001260begin
Jens Geyer5a781c22025-02-04 23:35:55 +01001261 if InputStream = nil
Jens Geyered994552019-11-09 23:24:52 +01001262 then raise TTransportExceptionNotOpen.Create('Cannot read from null inputstream' );
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001263
Jens Geyer5a781c22025-02-04 23:35:55 +01001264 Result := InputStream.Read( pBuf,buflen, off, len );
Jens Geyera019cda2019-11-09 23:24:52 +01001265 CountConsumedMessageBytes( result);
Jens Geyerd5436f52014-10-03 19:50:38 +02001266end;
1267
Jens Geyer17c3ad92017-09-05 20:31:27 +02001268procedure TStreamTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001269begin
Jens Geyer5a781c22025-02-04 23:35:55 +01001270 if OutputStream = nil
Jens Geyered994552019-11-09 23:24:52 +01001271 then raise TTransportExceptionNotOpen.Create('Cannot write to null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001272
Jens Geyer5a781c22025-02-04 23:35:55 +01001273 OutputStream.Write( pBuf, off, len );
1274end;
1275
1276
1277procedure TStreamTransportImpl.UpdateKnownMessageSize(const size : Int64);
1278var adjusted : Int64;
1279begin
1280 if InputStream = nil
1281 then adjusted := 0
1282 else begin
1283 adjusted := MaxMessageSize;
1284 if size > 0
1285 then adjusted := Math.Min( adjusted, size);
1286 if InputStream.CanSeek
1287 then adjusted := Math.Min( adjusted, InputStream.Size);
1288 end;
1289
1290 inherited UpdateKnownMessageSize( adjusted);
Jens Geyerd5436f52014-10-03 19:50:38 +02001291end;
1292
1293{ TBufferedTransportImpl }
1294
Jens Geyered994552019-11-09 23:24:52 +01001295constructor TBufferedTransportImpl.Create( const aTransport : IStreamTransport; const aBufSize: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001296begin
Jens Geyered994552019-11-09 23:24:52 +01001297 ASSERT( aTransport <> nil);
Jens Geyera019cda2019-11-09 23:24:52 +01001298 inherited Create( aTransport);
Jens Geyered994552019-11-09 23:24:52 +01001299 FBufSize := aBufSize;
Jens Geyerd5436f52014-10-03 19:50:38 +02001300 InitBuffers;
1301end;
1302
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001303procedure TBufferedTransportImpl.Close;
1304begin
Jens Geyera019cda2019-11-09 23:24:52 +01001305 InnerTransport.Close;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001306 FInputBuffer := nil;
Jens Geyered994552019-11-09 23:24:52 +01001307 FOutputBuffer := nil;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001308end;
1309
Jens Geyerd5436f52014-10-03 19:50:38 +02001310procedure TBufferedTransportImpl.Flush;
1311begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001312 if FOutputBuffer <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001313 FOutputBuffer.Flush;
1314 end;
1315end;
1316
1317function TBufferedTransportImpl.GetIsOpen: Boolean;
1318begin
Jens Geyera019cda2019-11-09 23:24:52 +01001319 Result := InnerTransport.IsOpen;
Jens Geyerd5436f52014-10-03 19:50:38 +02001320end;
1321
1322procedure TBufferedTransportImpl.InitBuffers;
1323begin
Jens Geyera019cda2019-11-09 23:24:52 +01001324 if InnerTransport.InputStream <> nil then begin
1325 FInputBuffer := TBufferedStreamImpl.Create( InnerTransport.InputStream, FBufSize );
Jens Geyerd5436f52014-10-03 19:50:38 +02001326 end;
Jens Geyera019cda2019-11-09 23:24:52 +01001327 if InnerTransport.OutputStream <> nil then begin
1328 FOutputBuffer := TBufferedStreamImpl.Create( InnerTransport.OutputStream, FBufSize );
Jens Geyerd5436f52014-10-03 19:50:38 +02001329 end;
1330end;
1331
1332procedure TBufferedTransportImpl.Open;
1333begin
Jens Geyera019cda2019-11-09 23:24:52 +01001334 InnerTransport.Open;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001335 InitBuffers; // we need to get the buffers to match FTransport substreams again
Jens Geyerd5436f52014-10-03 19:50:38 +02001336end;
1337
Jens Geyer17c3ad92017-09-05 20:31:27 +02001338function TBufferedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001339begin
Jens Geyered994552019-11-09 23:24:52 +01001340 if FInputBuffer <> nil
Jens Geyera019cda2019-11-09 23:24:52 +01001341 then Result := FInputBuffer.Read( pBuf,buflen, off, len )
Jens Geyered994552019-11-09 23:24:52 +01001342 else Result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +02001343end;
1344
Jens Geyer17c3ad92017-09-05 20:31:27 +02001345procedure TBufferedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001346begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001347 if FOutputBuffer <> nil then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001348 FOutputBuffer.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001349 end;
1350end;
1351
Jens Geyera019cda2019-11-09 23:24:52 +01001352procedure TBufferedTransportImpl.CheckReadBytesAvailable( const value : Int64);
1353var buffered, need : Int64;
Jens Geyer41f47af2019-11-09 23:24:52 +01001354begin
1355 need := value;
1356
1357 // buffered bytes
Jens Geyera019cda2019-11-09 23:24:52 +01001358 buffered := FInputBuffer.Size - FInputBuffer.Position;
1359 if buffered < need
1360 then InnerTransport.CheckReadBytesAvailable( need - buffered);
Jens Geyer41f47af2019-11-09 23:24:52 +01001361end;
1362
Jens Geyera019cda2019-11-09 23:24:52 +01001363
Jens Geyered994552019-11-09 23:24:52 +01001364{ TBufferedTransportImpl.TFactory }
Jens Geyerd5436f52014-10-03 19:50:38 +02001365
Jens Geyered994552019-11-09 23:24:52 +01001366function TBufferedTransportImpl.TFactory.GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +02001367begin
Jens Geyered994552019-11-09 23:24:52 +01001368 Result := TFramedTransportImpl.Create( aTransport);
Jens Geyerd5436f52014-10-03 19:50:38 +02001369end;
1370
Jens Geyered994552019-11-09 23:24:52 +01001371
1372{ TFramedTransportImpl }
1373
1374constructor TFramedTransportImpl.Create( const aTransport: ITransport);
Jens Geyerd5436f52014-10-03 19:50:38 +02001375begin
Jens Geyered994552019-11-09 23:24:52 +01001376 ASSERT( aTransport <> nil);
Jens Geyera019cda2019-11-09 23:24:52 +01001377 inherited Create( aTransport);
Jens Geyer2646bd62019-11-09 23:24:52 +01001378
Jens Geyerd5436f52014-10-03 19:50:38 +02001379 InitWriteBuffer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001380end;
1381
1382destructor TFramedTransportImpl.Destroy;
1383begin
1384 FWriteBuffer.Free;
Jens Geyera019cda2019-11-09 23:24:52 +01001385 FWriteBuffer := nil;
Jens Geyerd5436f52014-10-03 19:50:38 +02001386 FReadBuffer.Free;
Jens Geyera019cda2019-11-09 23:24:52 +01001387 FReadBuffer := nil;
Jens Geyerd5436f52014-10-03 19:50:38 +02001388 inherited;
1389end;
1390
Jens Geyer2646bd62019-11-09 23:24:52 +01001391procedure TFramedTransportImpl.Close;
1392begin
Jens Geyera019cda2019-11-09 23:24:52 +01001393 InnerTransport.Close;
Jens Geyer2646bd62019-11-09 23:24:52 +01001394end;
1395
Jens Geyerd5436f52014-10-03 19:50:38 +02001396procedure TFramedTransportImpl.Flush;
1397var
1398 buf : TBytes;
1399 len : Integer;
Jens Geyera019cda2019-11-09 23:24:52 +01001400 data_len : Int64;
Jens Geyerd5436f52014-10-03 19:50:38 +02001401begin
Jens Geyer528a0f02019-11-18 20:17:03 +01001402 if not IsOpen
1403 then raise TTransportExceptionNotOpen.Create('not open');
1404
Jens Geyerd5436f52014-10-03 19:50:38 +02001405 len := FWriteBuffer.Size;
1406 SetLength( buf, len);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001407 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001408 System.Move( FWriteBuffer.Memory^, buf[0], len );
1409 end;
1410
Jens Geyer2646bd62019-11-09 23:24:52 +01001411 data_len := len - SizeOf(TFramedHeader);
Jens Geyera019cda2019-11-09 23:24:52 +01001412 if (0 > data_len) or (data_len > Configuration.MaxFrameSize)
1413 then raise TTransportExceptionUnknown.Create('TFramedTransport.Flush: invalid frame size ('+IntToStr(data_len)+')')
1414 else UpdateKnownMessageSize( len);
Jens Geyerd5436f52014-10-03 19:50:38 +02001415
1416 InitWriteBuffer;
1417
1418 buf[0] := Byte($FF and (data_len shr 24));
1419 buf[1] := Byte($FF and (data_len shr 16));
1420 buf[2] := Byte($FF and (data_len shr 8));
1421 buf[3] := Byte($FF and data_len);
1422
Jens Geyera019cda2019-11-09 23:24:52 +01001423 InnerTransport.Write( buf, 0, len );
1424 InnerTransport.Flush;
Jens Geyerd5436f52014-10-03 19:50:38 +02001425end;
1426
1427function TFramedTransportImpl.GetIsOpen: Boolean;
1428begin
Jens Geyera019cda2019-11-09 23:24:52 +01001429 Result := InnerTransport.IsOpen;
Jens Geyerd5436f52014-10-03 19:50:38 +02001430end;
1431
Jens Geyerd5436f52014-10-03 19:50:38 +02001432procedure TFramedTransportImpl.InitWriteBuffer;
Jens Geyer2646bd62019-11-09 23:24:52 +01001433const DUMMY_HEADER : TFramedHeader = 0;
Jens Geyerd5436f52014-10-03 19:50:38 +02001434begin
Jens Geyer528a0f02019-11-18 20:17:03 +01001435 FreeAndNil( FWriteBuffer);
Jens Geyerf726ae32021-06-04 11:17:26 +02001436 FWriteBuffer := TThriftMemoryStream.Create(1024);
Jens Geyer2646bd62019-11-09 23:24:52 +01001437 FWriteBuffer.Write( DUMMY_HEADER, SizeOf(DUMMY_HEADER));
Jens Geyerd5436f52014-10-03 19:50:38 +02001438end;
1439
1440procedure TFramedTransportImpl.Open;
1441begin
Jens Geyera019cda2019-11-09 23:24:52 +01001442 InnerTransport.Open;
Jens Geyerd5436f52014-10-03 19:50:38 +02001443end;
1444
Jens Geyer17c3ad92017-09-05 20:31:27 +02001445function TFramedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001446var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001447begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001448 if len > (buflen-off)
1449 then len := buflen-off;
1450
Jens Geyer5089b0a2018-02-01 22:37:18 +01001451 pTmp := pBuf;
1452 Inc( pTmp, off);
1453
Jens Geyer17c3ad92017-09-05 20:31:27 +02001454 if (FReadBuffer <> nil) and (len > 0) then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001455 result := FReadBuffer.Read( pTmp^, len);
Jens Geyered994552019-11-09 23:24:52 +01001456 if result > 0 then Exit;
Jens Geyerd5436f52014-10-03 19:50:38 +02001457 end;
1458
1459 ReadFrame;
1460 if len > 0
Jens Geyer5089b0a2018-02-01 22:37:18 +01001461 then Result := FReadBuffer.Read( pTmp^, len)
Jens Geyerd5436f52014-10-03 19:50:38 +02001462 else Result := 0;
1463end;
1464
1465procedure TFramedTransportImpl.ReadFrame;
1466var
Jens Geyer2646bd62019-11-09 23:24:52 +01001467 i32rd : packed array[0..SizeOf(TFramedHeader)-1] of Byte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001468 size : Integer;
1469 buff : TBytes;
1470begin
Jens Geyera019cda2019-11-09 23:24:52 +01001471 InnerTransport.ReadAll( @i32rd[0], SizeOf(i32rd), 0, SizeOf(i32rd));
Jens Geyerd5436f52014-10-03 19:50:38 +02001472 size :=
1473 ((i32rd[0] and $FF) shl 24) or
1474 ((i32rd[1] and $FF) shl 16) or
1475 ((i32rd[2] and $FF) shl 8) or
1476 (i32rd[3] and $FF);
Jens Geyer2646bd62019-11-09 23:24:52 +01001477
1478 if size < 0 then begin
1479 Close();
1480 raise TTransportExceptionCorruptedData.Create('Read a negative frame size ('+IntToStr(size)+')');
1481 end;
1482
Jens Geyera019cda2019-11-09 23:24:52 +01001483 if Int64(size) > Int64(Configuration.MaxFrameSize) then begin
Jens Geyer2646bd62019-11-09 23:24:52 +01001484 Close();
Jens Geyer589ee5b2021-03-29 21:40:55 +02001485 if CharUtils.IsHtmlDoctype(size)
1486 then raise TTransportExceptionCorruptedData.Create('Remote end sends HTML instead of data')
1487 else raise TTransportExceptionCorruptedData.Create('Frame size ('+IntToStr(size)+') larger than allowed maximum ('+IntToStr(Configuration.MaxFrameSize)+')');
Jens Geyer2646bd62019-11-09 23:24:52 +01001488 end;
1489
Jens Geyera019cda2019-11-09 23:24:52 +01001490 UpdateKnownMessageSize(size + SizeOf(size));
1491
Jens Geyerd5436f52014-10-03 19:50:38 +02001492 SetLength( buff, size );
Jens Geyera019cda2019-11-09 23:24:52 +01001493 InnerTransport.ReadAll( buff, 0, size );
Jens Geyered994552019-11-09 23:24:52 +01001494
1495 FreeAndNil( FReadBuffer);
Jens Geyerf726ae32021-06-04 11:17:26 +02001496 FReadBuffer := TThriftMemoryStream.Create(1024);
Jens Geyera76e6c72017-09-08 21:03:30 +02001497 if Length(buff) > 0
1498 then FReadBuffer.Write( Pointer(@buff[0])^, size );
Jens Geyerd5436f52014-10-03 19:50:38 +02001499 FReadBuffer.Position := 0;
1500end;
1501
Jens Geyer17c3ad92017-09-05 20:31:27 +02001502procedure TFramedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001503var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001504begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001505 if len > 0 then begin
1506 pTmp := pBuf;
1507 Inc( pTmp, off);
1508
1509 FWriteBuffer.Write( pTmp^, len );
1510 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001511end;
1512
Jens Geyered994552019-11-09 23:24:52 +01001513
Jens Geyera019cda2019-11-09 23:24:52 +01001514procedure TFramedTransportImpl.CheckReadBytesAvailable( const value : Int64);
1515var buffered, need : Int64;
Jens Geyer41f47af2019-11-09 23:24:52 +01001516begin
Jens Geyera019cda2019-11-09 23:24:52 +01001517 need := value;
Jens Geyer41f47af2019-11-09 23:24:52 +01001518
Jens Geyera019cda2019-11-09 23:24:52 +01001519 // buffered bytes
1520 buffered := FReadBuffer.Size - FReadBuffer.Position;
1521 if buffered < need
1522 then InnerTransport.CheckReadBytesAvailable( need - buffered);
Jens Geyer41f47af2019-11-09 23:24:52 +01001523end;
1524
1525
Jens Geyerd5436f52014-10-03 19:50:38 +02001526{ TFramedTransport.TFactory }
1527
Jens Geyered994552019-11-09 23:24:52 +01001528function TFramedTransportImpl.TFactory.GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +02001529begin
Jens Geyered994552019-11-09 23:24:52 +01001530 Result := TFramedTransportImpl.Create( aTransport);
Jens Geyerd5436f52014-10-03 19:50:38 +02001531end;
1532
1533{ TTcpSocketStreamImpl }
1534
1535procedure TTcpSocketStreamImpl.Close;
1536begin
1537 FTcpClient.Close;
1538end;
1539
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001540{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +01001541constructor TTcpSocketStreamImpl.Create( const aTcpClient: TCustomIpClient; const aTimeout : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001542begin
1543 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +01001544 FTcpClient := aTcpClient;
Jens Geyerd5436f52014-10-03 19:50:38 +02001545 FTimeout := aTimeout;
1546end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001547{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +01001548constructor TTcpSocketStreamImpl.Create( const aTcpClient: TSocket; const aTimeout : Longword);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001549begin
1550 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +01001551 FTcpClient := aTcpClient;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001552 if aTimeout = 0 then
1553 FTcpClient.RecvTimeout := SLEEP_TIME
1554 else
1555 FTcpClient.RecvTimeout := aTimeout;
1556 FTcpClient.SendTimeout := aTimeout;
1557end;
1558{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001559
1560procedure TTcpSocketStreamImpl.Flush;
1561begin
Jens Geyera019cda2019-11-09 23:24:52 +01001562 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +02001563end;
1564
Jens Geyera019cda2019-11-09 23:24:52 +01001565
Jens Geyerd5436f52014-10-03 19:50:38 +02001566function TTcpSocketStreamImpl.IsOpen: Boolean;
1567begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001568{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001569 Result := FTcpClient.Active;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001570{$ELSE}
1571 Result := FTcpClient.IsOpen;
1572{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001573end;
1574
1575procedure TTcpSocketStreamImpl.Open;
1576begin
1577 FTcpClient.Open;
1578end;
1579
1580
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001581{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001582function TTcpSocketStreamImpl.Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
1583 TimeOut: Integer; var wsaError : Integer): Integer;
1584var
1585 ReadFds: TFDset;
1586 ReadFdsptr: PFDset;
1587 WriteFds: TFDset;
1588 WriteFdsptr: PFDset;
1589 ExceptFds: TFDset;
1590 ExceptFdsptr: PFDset;
1591 tv: timeval;
1592 Timeptr: PTimeval;
1593 socket : TSocket;
1594begin
1595 if not FTcpClient.Active then begin
1596 wsaError := WSAEINVAL;
1597 Exit( SOCKET_ERROR);
1598 end;
1599
1600 socket := FTcpClient.Handle;
1601
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001602 if Assigned(ReadReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001603 ReadFdsptr := @ReadFds;
1604 FD_ZERO(ReadFds);
1605 FD_SET(socket, ReadFds);
1606 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001607 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001608 ReadFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001609 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001610
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001611 if Assigned(WriteReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001612 WriteFdsptr := @WriteFds;
1613 FD_ZERO(WriteFds);
1614 FD_SET(socket, WriteFds);
1615 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001616 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001617 WriteFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001618 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001619
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001620 if Assigned(ExceptFlag) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001621 ExceptFdsptr := @ExceptFds;
1622 FD_ZERO(ExceptFds);
1623 FD_SET(socket, ExceptFds);
1624 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001625 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001626 ExceptFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001627 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001628
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001629 if TimeOut >= 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001630 tv.tv_sec := TimeOut div 1000;
1631 tv.tv_usec := 1000 * (TimeOut mod 1000);
1632 Timeptr := @tv;
1633 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001634 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001635 Timeptr := nil; // wait forever
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001636 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001637
1638 wsaError := 0;
1639 try
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001640 {$IFDEF MSWINDOWS}
1641 {$IFDEF OLD_UNIT_NAMES}
1642 result := WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1643 {$ELSE}
1644 result := Winapi.WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1645 {$ENDIF}
1646 {$ENDIF}
1647 {$IFDEF LINUX}
1648 result := Libc.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1649 {$ENDIF}
Jens Geyera019cda2019-11-09 23:24:52 +01001650
Jens Geyerd5436f52014-10-03 19:50:38 +02001651 if result = SOCKET_ERROR
1652 then wsaError := WSAGetLastError;
1653
1654 except
1655 result := SOCKET_ERROR;
1656 end;
1657
1658 if Assigned(ReadReady) then
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001659 ReadReady^ := FD_ISSET(socket, ReadFds);
1660
Jens Geyerd5436f52014-10-03 19:50:38 +02001661 if Assigned(WriteReady) then
1662 WriteReady^ := FD_ISSET(socket, WriteFds);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001663
Jens Geyerd5436f52014-10-03 19:50:38 +02001664 if Assigned(ExceptFlag) then
1665 ExceptFlag^ := FD_ISSET(socket, ExceptFds);
1666end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001667{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001668
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001669{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001670function TTcpSocketStreamImpl.WaitForData( TimeOut : Integer; pBuf : Pointer;
1671 DesiredBytes : Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001672 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001673var bCanRead, bError : Boolean;
1674 retval : Integer;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001675const
1676 MSG_PEEK = {$IFDEF OLD_UNIT_NAMES} WinSock.MSG_PEEK {$ELSE} Winapi.WinSock.MSG_PEEK {$ENDIF};
Jens Geyerd5436f52014-10-03 19:50:38 +02001677begin
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001678 bytesReady := 0;
1679
Jens Geyerd5436f52014-10-03 19:50:38 +02001680 // The select function returns the total number of socket handles that are ready
1681 // and contained in the fd_set structures, zero if the time limit expired,
1682 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1683 // WSAGetLastError can be used to retrieve a specific error code.
1684 retval := Self.Select( @bCanRead, nil, @bError, TimeOut, wsaError);
1685 if retval = SOCKET_ERROR
1686 then Exit( TWaitForData.wfd_Error);
1687 if (retval = 0) or not bCanRead
1688 then Exit( TWaitForData.wfd_Timeout);
1689
1690 // recv() returns the number of bytes received, or -1 if an error occurred.
1691 // The return value will be 0 when the peer has performed an orderly shutdown.
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001692
1693 retval := recv( FTcpClient.Handle, pBuf^, DesiredBytes, MSG_PEEK);
Jens Geyerd5436f52014-10-03 19:50:38 +02001694 if retval <= 0
1695 then Exit( TWaitForData.wfd_Error);
1696
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001697 // at least we have some data
1698 bytesReady := Min( retval, DesiredBytes);
1699 result := TWaitForData.wfd_HaveData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001700end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001701{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001702
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001703{$IFDEF OLD_SOCKETS}
Jens Geyer17c3ad92017-09-05 20:31:27 +02001704function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001705// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001706var wfd : TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001707 wsaError,
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001708 msecs : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001709 nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001710 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001711begin
1712 inherited;
1713
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001714 if FTimeout > 0
1715 then msecs := FTimeout
1716 else msecs := DEFAULT_THRIFT_TIMEOUT;
1717
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001718 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001719 pTmp := pBuf;
1720 Inc( pTmp, offset);
Jens Geyerc140bb92019-11-27 22:18:12 +01001721 while (count > 0) and (result = 0) do begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001722
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001723 while TRUE do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001724 wfd := WaitForData( msecs, pTmp, count, wsaError, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001725 case wfd of
Jens Geyer65b17462016-03-09 00:07:46 +01001726 TWaitForData.wfd_Error : Exit;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001727 TWaitForData.wfd_HaveData : Break;
1728 TWaitForData.wfd_Timeout : begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001729 if (FTimeout = 0)
1730 then Exit
Jens Geyera019cda2019-11-09 23:24:52 +01001731 else raise TTransportExceptionTimedOut.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001732 end;
1733 else
1734 ASSERT( FALSE);
Jens Geyerd5436f52014-10-03 19:50:38 +02001735 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001736 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001737
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001738 // reduce the timeout once we got data
1739 if FTimeout > 0
1740 then msecs := FTimeout div 10
1741 else msecs := DEFAULT_THRIFT_TIMEOUT div 10;
1742 msecs := Max( msecs, 200);
1743
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001744 ASSERT( nBytes <= count);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001745 nBytes := FTcpClient.ReceiveBuf( pTmp^, nBytes);
1746 Inc( pTmp, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001747 Dec( count, nBytes);
1748 Inc( result, nBytes);
1749 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001750end;
1751
1752function TTcpSocketStreamImpl.ToArray: TBytes;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001753// old sockets version
1754var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001755begin
1756 len := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001757 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001758 len := FTcpClient.BytesReceived;
1759 end;
1760
1761 SetLength( Result, len );
1762
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001763 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001764 FTcpClient.ReceiveBuf( Pointer(@Result[0])^, len);
1765 end;
1766end;
1767
Jens Geyer17c3ad92017-09-05 20:31:27 +02001768procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001769// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001770var bCanWrite, bError : Boolean;
1771 retval, wsaError : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001772 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001773begin
1774 inherited;
1775
1776 if not FTcpClient.Active
Jens Geyere0e32402016-04-20 21:50:48 +02001777 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerd5436f52014-10-03 19:50:38 +02001778
1779 // The select function returns the total number of socket handles that are ready
1780 // and contained in the fd_set structures, zero if the time limit expired,
1781 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1782 // WSAGetLastError can be used to retrieve a specific error code.
1783 retval := Self.Select( nil, @bCanWrite, @bError, FTimeOut, wsaError);
1784 if retval = SOCKET_ERROR
Jens Geyere0e32402016-04-20 21:50:48 +02001785 then raise TTransportExceptionUnknown.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001786
Jens Geyerd5436f52014-10-03 19:50:38 +02001787 if (retval = 0)
Jens Geyere0e32402016-04-20 21:50:48 +02001788 then raise TTransportExceptionTimedOut.Create('timed out');
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001789
Jens Geyerd5436f52014-10-03 19:50:38 +02001790 if bError or not bCanWrite
Jens Geyere0e32402016-04-20 21:50:48 +02001791 then raise TTransportExceptionUnknown.Create('unknown error');
Jens Geyerd5436f52014-10-03 19:50:38 +02001792
Jens Geyer5089b0a2018-02-01 22:37:18 +01001793 pTmp := pBuf;
1794 Inc( pTmp, offset);
1795 FTcpClient.SendBuf( pTmp^, count);
Jens Geyerd5436f52014-10-03 19:50:38 +02001796end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001797
1798{$ELSE}
1799
Jens Geyer17c3ad92017-09-05 20:31:27 +02001800function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001801// new sockets version
1802var nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001803 pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001804begin
1805 inherited;
1806
1807 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001808 pTmp := pBuf;
1809 Inc( pTmp, offset);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001810 while count > 0 do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001811 nBytes := FTcpClient.Read( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001812 if nBytes = 0 then Exit;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001813 Inc( pTmp, nBytes);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001814 Dec( count, nBytes);
1815 Inc( result, nBytes);
1816 end;
1817end;
1818
1819function TTcpSocketStreamImpl.ToArray: TBytes;
1820// new sockets version
1821var len : Integer;
1822begin
1823 len := 0;
1824 try
1825 if FTcpClient.Peek then
1826 repeat
1827 SetLength(Result, Length(Result) + 1024);
1828 len := FTcpClient.Read(Result[Length(Result) - 1024], 1024);
1829 until len < 1024;
1830 except
1831 on TTransportException do begin { don't allow default exceptions } end;
1832 else raise;
1833 end;
1834 if len > 0 then
1835 SetLength(Result, Length(Result) - 1024 + len);
1836end;
1837
Jens Geyer17c3ad92017-09-05 20:31:27 +02001838procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001839// new sockets version
Jens Geyer5089b0a2018-02-01 22:37:18 +01001840var pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001841begin
1842 inherited;
1843
1844 if not FTcpClient.IsOpen
Kyle Johnsone363a342016-04-22 19:11:16 -05001845 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001846
Jens Geyer5089b0a2018-02-01 22:37:18 +01001847 pTmp := pBuf;
1848 Inc( pTmp, offset);
1849 FTcpClient.Write( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001850end;
1851
Jens Geyer23d67462015-12-19 11:44:57 +01001852{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001853
Jens Geyerd5436f52014-10-03 19:50:38 +02001854
1855end.