blob: bede57cd87d0913ebd9fda427869522f6f419ca0 [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 Geyerd5436f52014-10-03 19:50:38 +020041 Thrift.Collections,
Jens Geyer606f1ef2018-04-09 23:09:41 +020042 Thrift.Exception,
Jens Geyerd5436f52014-10-03 19:50:38 +020043 Thrift.Utils,
Jens Geyer02230912019-04-03 01:12:51 +020044 Thrift.WinHTTP,
Nick4f5229e2016-04-14 16:43:22 +030045 Thrift.Stream;
Jens Geyerd5436f52014-10-03 19:50:38 +020046
47type
48 ITransport = interface
Jens Geyer17c3ad92017-09-05 20:31:27 +020049 ['{DB84961E-8BB3-4532-99E1-A8C7AC2300F7}']
Jens Geyerd5436f52014-10-03 19:50:38 +020050 function GetIsOpen: Boolean;
51 property IsOpen: Boolean read GetIsOpen;
52 function Peek: Boolean;
53 procedure Open;
54 procedure Close;
Jens Geyer17c3ad92017-09-05 20:31:27 +020055 function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
56 function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
57 function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
58 function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020059 procedure Write( const buf: TBytes); overload;
60 procedure Write( const buf: TBytes; off: Integer; len: Integer); overload;
Jens Geyer17c3ad92017-09-05 20:31:27 +020061 procedure Write( const pBuf : Pointer; off, len : Integer); overload;
62 procedure Write( const pBuf : Pointer; len : Integer); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020063 procedure Flush;
64 end;
65
66 TTransportImpl = class( TInterfacedObject, ITransport)
Jens Geyerfad7fd32019-11-09 23:24:52 +010067 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +020068 function GetIsOpen: Boolean; virtual; abstract;
69 property IsOpen: Boolean read GetIsOpen;
70 function Peek: Boolean; virtual;
71 procedure Open(); virtual; abstract;
72 procedure Close(); virtual; abstract;
Jens Geyer17c3ad92017-09-05 20:31:27 +020073 function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
74 function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual; abstract;
75 function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
76 function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual;
77 procedure Write( const buf: TBytes); overload; inline;
78 procedure Write( const buf: TBytes; off: Integer; len: Integer); overload; inline;
79 procedure Write( const pBuf : Pointer; len : Integer); overload; inline;
80 procedure Write( const pBuf : Pointer; off, len : Integer); overload; virtual; abstract;
Jens Geyerd5436f52014-10-03 19:50:38 +020081 procedure Flush; virtual;
82 end;
83
Jens Geyer9f11c1e2019-11-09 19:39:20 +010084 TTransportException = class abstract( TException)
Jens Geyerd5436f52014-10-03 19:50:38 +020085 public
86 type
87 TExceptionType = (
88 Unknown,
89 NotOpen,
90 AlreadyOpen,
91 TimedOut,
Jens Geyerbea9bbe2016-04-20 00:02:40 +020092 EndOfFile,
93 BadArgs,
Jens Geyer2646bd62019-11-09 23:24:52 +010094 Interrupted,
95 CorruptedData
Jens Geyerd5436f52014-10-03 19:50:38 +020096 );
Jens Geyerfad7fd32019-11-09 23:24:52 +010097 strict protected
Jens Geyere0e32402016-04-20 21:50:48 +020098 constructor HiddenCreate(const Msg: string);
Jens Geyer9f11c1e2019-11-09 19:39:20 +010099 class function GetType: TExceptionType; virtual; abstract;
Jens Geyerd5436f52014-10-03 19:50:38 +0200100 public
Jens Geyere0e32402016-04-20 21:50:48 +0200101 class function Create( AType: TExceptionType): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
102 class function Create( const msg: string): TTransportException; reintroduce; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
103 class function Create( AType: TExceptionType; const msg: string): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
104 property Type_: TExceptionType read GetType;
Jens Geyerd5436f52014-10-03 19:50:38 +0200105 end;
106
Jens Geyere0e32402016-04-20 21:50:48 +0200107 // Needed to remove deprecation warning
108 TTransportExceptionSpecialized = class abstract (TTransportException)
109 public
110 constructor Create(const Msg: string);
111 end;
112
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100113 TTransportExceptionUnknown = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100114 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100115 class function GetType: TTransportException.TExceptionType; override;
116 end;
117
118 TTransportExceptionNotOpen = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100119 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100120 class function GetType: TTransportException.TExceptionType; override;
121 end;
122
123 TTransportExceptionAlreadyOpen = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100124 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100125 class function GetType: TTransportException.TExceptionType; override;
126 end;
127
128 TTransportExceptionTimedOut = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100129 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100130 class function GetType: TTransportException.TExceptionType; override;
131 end;
132
133 TTransportExceptionEndOfFile = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100134 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100135 class function GetType: TTransportException.TExceptionType; override;
136 end;
137
138 TTransportExceptionBadArgs = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100139 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100140 class function GetType: TTransportException.TExceptionType; override;
141 end;
142
143 TTransportExceptionInterrupted = class (TTransportExceptionSpecialized)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100144 strict protected
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100145 class function GetType: TTransportException.TExceptionType; override;
146 end;
Jens Geyere0e32402016-04-20 21:50:48 +0200147
Jens Geyer2646bd62019-11-09 23:24:52 +0100148 TTransportExceptionCorruptedData = class (TTransportExceptionSpecialized)
149 protected
150 class function GetType: TTransportException.TExceptionType; override;
151 end;
152
Jens Geyer47f63172019-06-06 22:42:58 +0200153 TSecureProtocol = (
154 SSL_2, SSL_3, TLS_1, // outdated, for compatibilty only
155 TLS_1_1, TLS_1_2 // secure (as of today)
156 );
157
158 TSecureProtocols = set of TSecureProtocol;
159
Jens Geyerd5436f52014-10-03 19:50:38 +0200160 IHTTPClient = interface( ITransport )
Jens Geyer47f63172019-06-06 22:42:58 +0200161 ['{7BF615DD-8680-4004-A5B2-88947BA3BA3D}']
Jens Geyer20e727e2018-06-22 22:39:57 +0200162 procedure SetDnsResolveTimeout(const Value: Integer);
163 function GetDnsResolveTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200164 procedure SetConnectionTimeout(const Value: Integer);
165 function GetConnectionTimeout: Integer;
Jens Geyer20e727e2018-06-22 22:39:57 +0200166 procedure SetSendTimeout(const Value: Integer);
167 function GetSendTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200168 procedure SetReadTimeout(const Value: Integer);
169 function GetReadTimeout: Integer;
170 function GetCustomHeaders: IThriftDictionary<string,string>;
171 procedure SendRequest;
Jens Geyer47f63172019-06-06 22:42:58 +0200172 function GetSecureProtocols : TSecureProtocols;
173 procedure SetSecureProtocols( const value : TSecureProtocols);
Jens Geyer20e727e2018-06-22 22:39:57 +0200174
175 property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200176 property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
Jens Geyer20e727e2018-06-22 22:39:57 +0200177 property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200178 property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
179 property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
Jens Geyer47f63172019-06-06 22:42:58 +0200180 property SecureProtocols : TSecureProtocols read GetSecureProtocols write SetSecureProtocols;
Jens Geyerd5436f52014-10-03 19:50:38 +0200181 end;
182
Jens Geyerd5436f52014-10-03 19:50:38 +0200183 IServerTransport = interface
184 ['{C43B87ED-69EA-47C4-B77C-15E288252900}']
185 procedure Listen;
186 procedure Close;
187 function Accept( const fnAccepting: TProc): ITransport;
188 end;
189
190 TServerTransportImpl = class( TInterfacedObject, IServerTransport)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100191 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200192 procedure Listen; virtual; abstract;
193 procedure Close; virtual; abstract;
194 function Accept( const fnAccepting: TProc): ITransport; virtual; abstract;
195 end;
196
197 ITransportFactory = interface
198 ['{DD809446-000F-49E1-9BFF-E0D0DC76A9D7}']
199 function GetTransport( const ATrans: ITransport): ITransport;
200 end;
201
202 TTransportFactoryImpl = class( TInterfacedObject, ITransportFactory)
Jens Geyered994552019-11-09 23:24:52 +0100203 function GetTransport( const aTransport: ITransport): ITransport; virtual;
Jens Geyerd5436f52014-10-03 19:50:38 +0200204 end;
205
206 TTcpSocketStreamImpl = class( TThriftStreamImpl )
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200207{$IFDEF OLD_SOCKETS}
Jens Geyerfad7fd32019-11-09 23:24:52 +0100208 strict private type
Jens Geyerd5436f52014-10-03 19:50:38 +0200209 TWaitForData = ( wfd_HaveData, wfd_Timeout, wfd_Error);
Jens Geyerfad7fd32019-11-09 23:24:52 +0100210 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200211 FTcpClient : TCustomIpClient;
Jens Geyerd5436f52014-10-03 19:50:38 +0200212 FTimeout : Integer;
213 function Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
214 TimeOut: Integer; var wsaError : Integer): Integer;
215 function WaitForData( TimeOut : Integer; pBuf : Pointer; DesiredBytes: Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +0200216 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200217{$ELSE}
218 FTcpClient: TSocket;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100219 strict protected const
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200220 SLEEP_TIME = 200;
221{$ENDIF}
Jens Geyerfad7fd32019-11-09 23:24:52 +0100222 strict protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200223 procedure Write( const pBuf : Pointer; offset, count: Integer); override;
224 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200225 procedure Open; override;
226 procedure Close; override;
227 procedure Flush; override;
228
229 function IsOpen: Boolean; override;
230 function ToArray: TBytes; override;
231 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200232{$IFDEF OLD_SOCKETS}
233 constructor Create( const ATcpClient: TCustomIpClient; const aTimeout : Integer = 0);
234{$ELSE}
235 constructor Create( const ATcpClient: TSocket; const aTimeout : Longword = 0);
236{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200237 end;
238
239 IStreamTransport = interface( ITransport )
240 ['{A8479B47-2A3E-4421-A9A0-D5A9EDCC634A}']
241 function GetInputStream: IThriftStream;
242 function GetOutputStream: IThriftStream;
243 property InputStream : IThriftStream read GetInputStream;
244 property OutputStream : IThriftStream read GetOutputStream;
245 end;
246
247 TStreamTransportImpl = class( TTransportImpl, IStreamTransport)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100248 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200249 FInputStream : IThriftStream;
250 FOutputStream : IThriftStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100251 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200252 function GetIsOpen: Boolean; override;
253
254 function GetInputStream: IThriftStream;
255 function GetOutputStream: IThriftStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200256
Jens Geyered994552019-11-09 23:24:52 +0100257 protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200258 procedure Open; override;
259 procedure Close; override;
260 procedure Flush; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200261 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
262 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyered994552019-11-09 23:24:52 +0100263 public
264 constructor Create( const aInputStream, aOutputStream : IThriftStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200265 destructor Destroy; override;
Jens Geyered994552019-11-09 23:24:52 +0100266
267 property InputStream : IThriftStream read GetInputStream;
268 property OutputStream : IThriftStream read GetOutputStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200269 end;
270
271 TBufferedStreamImpl = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100272 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200273 FStream : IThriftStream;
274 FBufSize : Integer;
275 FReadBuffer : TMemoryStream;
276 FWriteBuffer : TMemoryStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100277 strict protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200278 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
279 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200280 procedure Open; override;
281 procedure Close; override;
282 procedure Flush; override;
283 function IsOpen: Boolean; override;
284 function ToArray: TBytes; override;
285 public
Jens Geyered994552019-11-09 23:24:52 +0100286 constructor Create( const aStream: IThriftStream; const aBufSize : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200287 destructor Destroy; override;
288 end;
289
290 TServerSocketImpl = class( TServerTransportImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100291 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200292{$IFDEF OLD_SOCKETS}
293 FServer : TTcpServer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200294 FPort : Integer;
295 FClientTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200296{$ELSE}
297 FServer: TServerSocket;
298{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200299 FUseBufferedSocket : Boolean;
300 FOwnsServer : Boolean;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100301 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200302 function Accept( const fnAccepting: TProc) : ITransport; override;
303 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200304{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100305 constructor Create( const aServer: TTcpServer; const aClientTimeout: Integer = 0); overload;
306 constructor Create( const aPort: Integer; const aClientTimeout: Integer = 0; const aUseBufferedSockets: Boolean = FALSE); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200307{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +0100308 constructor Create( const aServer: TServerSocket; const aClientTimeout: Longword = 0); overload;
309 constructor Create( const aPort: Integer; const aClientTimeout: Longword = 0; const aUseBufferedSockets: Boolean = FALSE); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200310{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200311 destructor Destroy; override;
312 procedure Listen; override;
313 procedure Close; override;
314 end;
315
316 TBufferedTransportImpl = class( TTransportImpl )
Jens Geyerfad7fd32019-11-09 23:24:52 +0100317 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200318 FInputBuffer : IThriftStream;
319 FOutputBuffer : IThriftStream;
320 FTransport : IStreamTransport;
321 FBufSize : Integer;
322
323 procedure InitBuffers;
324 function GetUnderlyingTransport: ITransport;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100325 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200326 function GetIsOpen: Boolean; override;
327 procedure Flush; override;
328 public
Jens Geyered994552019-11-09 23:24:52 +0100329 type
330 TFactory = class( TTransportFactoryImpl )
331 public
332 function GetTransport( const aTransport: ITransport): ITransport; override;
333 end;
334
335 constructor Create( const aTransport : IStreamTransport; const aBufSize: Integer = 1024);
Jens Geyerd5436f52014-10-03 19:50:38 +0200336 procedure Open(); override;
337 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200338 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
339 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200340 property UnderlyingTransport: ITransport read GetUnderlyingTransport;
341 property IsOpen: Boolean read GetIsOpen;
342 end;
343
344 TSocketImpl = class(TStreamTransportImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100345 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200346{$IFDEF OLD_SOCKETS}
347 FClient : TCustomIpClient;
348{$ELSE}
349 FClient: TSocket;
350{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200351 FOwnsClient : Boolean;
352 FHost : string;
353 FPort : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200354{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200355 FTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200356{$ELSE}
357 FTimeout : Longword;
358{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200359
360 procedure InitSocket;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100361 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200362 function GetIsOpen: Boolean; override;
363 public
364 procedure Open; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200365{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100366 constructor Create( const aClient : TCustomIpClient; const aOwnsClient : Boolean; const aTimeout: Integer = 0); overload;
367 constructor Create( const aHost: string; const aPort: Integer; const aTimeout: Integer = 0); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200368{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +0100369 constructor Create( const aClient: TSocket; const aOwnsClient: Boolean); overload;
370 constructor Create( const aHost: string; const aPort: Integer; const aTimeout: Longword = 0); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200371{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200372 destructor Destroy; override;
373 procedure Close; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200374{$IFDEF OLD_SOCKETS}
375 property TcpClient: TCustomIpClient read FClient;
376{$ELSE}
377 property TcpClient: TSocket read FClient;
378{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200379 property Host : string read FHost;
380 property Port: Integer read FPort;
381 end;
382
383 TFramedTransportImpl = class( TTransportImpl)
Jens Geyer2646bd62019-11-09 23:24:52 +0100384 strict protected const
385 DEFAULT_MAX_LENGTH = 16384000; // this value is used by all Thrift libraries
386 strict protected type
387 TFramedHeader = Int32;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100388 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200389 FTransport : ITransport;
390 FWriteBuffer : TMemoryStream;
391 FReadBuffer : TMemoryStream;
Jens Geyer2646bd62019-11-09 23:24:52 +0100392 FMaxFrameSize : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200393
Jens Geyer2646bd62019-11-09 23:24:52 +0100394 procedure InitMaxFrameSize;
Jens Geyerd5436f52014-10-03 19:50:38 +0200395 procedure InitWriteBuffer;
396 procedure ReadFrame;
Jens Geyerd5436f52014-10-03 19:50:38 +0200397
398 procedure Open(); override;
399 function GetIsOpen: Boolean; override;
400
401 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200402 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
403 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200404 procedure Flush; override;
Jens Geyered994552019-11-09 23:24:52 +0100405 public
406 type
407 TFactory = class( TTransportFactoryImpl )
408 public
409 function GetTransport( const aTransport: ITransport): ITransport; override;
410 end;
411
412 constructor Create( const aTransport: ITransport); overload;
413 destructor Destroy; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200414 end;
415
Jens Geyerd5436f52014-10-03 19:50:38 +0200416
417const
418 DEFAULT_THRIFT_TIMEOUT = 5 * 1000; // ms
Jens Geyer47f63172019-06-06 22:42:58 +0200419 DEFAULT_THRIFT_SECUREPROTOCOLS = [ TSecureProtocol.TLS_1_1, TSecureProtocol.TLS_1_2];
420
Jens Geyerd5436f52014-10-03 19:50:38 +0200421implementation
422
Jens Geyered994552019-11-09 23:24:52 +0100423
Jens Geyerd5436f52014-10-03 19:50:38 +0200424{ TTransportImpl }
425
426procedure TTransportImpl.Flush;
427begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200428 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200429end;
430
431function TTransportImpl.Peek: Boolean;
432begin
433 Result := IsOpen;
434end;
435
Jens Geyer17c3ad92017-09-05 20:31:27 +0200436function TTransportImpl.Read(var buf: TBytes; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200437begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200438 if Length(buf) > 0
439 then result := Read( @buf[0], Length(buf), off, len)
440 else result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200441end;
442
443function TTransportImpl.ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;
444begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200445 if Length(buf) > 0
446 then result := ReadAll( @buf[0], Length(buf), off, len)
447 else result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200448end;
449
Jens Geyer17c3ad92017-09-05 20:31:27 +0200450function TTransportImpl.ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
451var ret : Integer;
452begin
453 result := 0;
454 while result < len do begin
455 ret := Read( pBuf, buflen, off + result, len - result);
456 if ret > 0
457 then Inc( result, ret)
458 else raise TTransportExceptionNotOpen.Create( 'Cannot read, Remote side has closed' );
459 end;
460end;
461
Jens Geyered994552019-11-09 23:24:52 +0100462procedure TTransportImpl.Write( const buf: TBytes);
463begin
464 if Length(buf) > 0
465 then Write( @buf[0], 0, Length(buf));
466end;
467
468procedure TTransportImpl.Write( const buf: TBytes; off: Integer; len: Integer);
469begin
470 if Length(buf) > 0
471 then Write( @buf[0], off, len);
472end;
473
Jens Geyer17c3ad92017-09-05 20:31:27 +0200474procedure TTransportImpl.Write( const pBuf : Pointer; len : Integer);
475begin
476 Self.Write( pBuf, 0, len);
Jens Geyerd5436f52014-10-03 19:50:38 +0200477end;
478
Jens Geyered994552019-11-09 23:24:52 +0100479
Jens Geyerd5436f52014-10-03 19:50:38 +0200480{ TTransportException }
481
Jens Geyere0e32402016-04-20 21:50:48 +0200482constructor TTransportException.HiddenCreate(const Msg: string);
483begin
484 inherited Create(Msg);
485end;
486
Jens Geyered994552019-11-09 23:24:52 +0100487class function TTransportException.Create(aType: TExceptionType): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200488begin
489 //no inherited;
Jens Geyere0e32402016-04-20 21:50:48 +0200490{$WARN SYMBOL_DEPRECATED OFF}
Jens Geyered994552019-11-09 23:24:52 +0100491 Result := Create(aType, '')
Jens Geyere0e32402016-04-20 21:50:48 +0200492{$WARN SYMBOL_DEPRECATED DEFAULT}
Jens Geyerd5436f52014-10-03 19:50:38 +0200493end;
494
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100495class function TTransportException.Create(aType: TExceptionType; const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200496begin
Jens Geyered994552019-11-09 23:24:52 +0100497 case aType of
Jens Geyere0e32402016-04-20 21:50:48 +0200498 TExceptionType.NotOpen: Result := TTransportExceptionNotOpen.Create(msg);
499 TExceptionType.AlreadyOpen: Result := TTransportExceptionAlreadyOpen.Create(msg);
500 TExceptionType.TimedOut: Result := TTransportExceptionTimedOut.Create(msg);
501 TExceptionType.EndOfFile: Result := TTransportExceptionEndOfFile.Create(msg);
502 TExceptionType.BadArgs: Result := TTransportExceptionBadArgs.Create(msg);
503 TExceptionType.Interrupted: Result := TTransportExceptionInterrupted.Create(msg);
504 else
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100505 ASSERT( TExceptionType.Unknown = aType);
Jens Geyere0e32402016-04-20 21:50:48 +0200506 Result := TTransportExceptionUnknown.Create(msg);
507 end;
Jens Geyerd5436f52014-10-03 19:50:38 +0200508end;
509
Jens Geyere0e32402016-04-20 21:50:48 +0200510class function TTransportException.Create(const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200511begin
Jens Geyere0e32402016-04-20 21:50:48 +0200512 Result := TTransportExceptionUnknown.Create(Msg);
513end;
514
515{ TTransportExceptionSpecialized }
516
517constructor TTransportExceptionSpecialized.Create(const Msg: string);
518begin
519 inherited HiddenCreate(Msg);
Jens Geyerd5436f52014-10-03 19:50:38 +0200520end;
521
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100522{ specialized TTransportExceptions }
523
524class function TTransportExceptionUnknown.GetType: TTransportException.TExceptionType;
525begin
526 result := TExceptionType.Unknown;
527end;
528
529class function TTransportExceptionNotOpen.GetType: TTransportException.TExceptionType;
530begin
531 result := TExceptionType.NotOpen;
532end;
533
534class function TTransportExceptionAlreadyOpen.GetType: TTransportException.TExceptionType;
535begin
536 result := TExceptionType.AlreadyOpen;
537end;
538
539class function TTransportExceptionTimedOut.GetType: TTransportException.TExceptionType;
540begin
541 result := TExceptionType.TimedOut;
542end;
543
544class function TTransportExceptionEndOfFile.GetType: TTransportException.TExceptionType;
545begin
546 result := TExceptionType.EndOfFile;
547end;
548
549class function TTransportExceptionBadArgs.GetType: TTransportException.TExceptionType;
550begin
551 result := TExceptionType.BadArgs;
552end;
553
554class function TTransportExceptionInterrupted.GetType: TTransportException.TExceptionType;
555begin
556 result := TExceptionType.Interrupted;
557end;
558
Jens Geyer2646bd62019-11-09 23:24:52 +0100559class function TTransportExceptionCorruptedData.GetType: TTransportException.TExceptionType;
560begin
561 result := TExceptionType.CorruptedData;
562end;
563
Jens Geyerd5436f52014-10-03 19:50:38 +0200564{ TTransportFactoryImpl }
565
Jens Geyered994552019-11-09 23:24:52 +0100566function TTransportFactoryImpl.GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +0200567begin
Jens Geyered994552019-11-09 23:24:52 +0100568 Result := aTransport;
Jens Geyerd5436f52014-10-03 19:50:38 +0200569end;
570
571{ TServerSocket }
572
Jens Geyer23d67462015-12-19 11:44:57 +0100573{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100574constructor TServerSocketImpl.Create( const aServer: TTcpServer; const aClientTimeout : Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200575{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +0100576constructor TServerSocketImpl.Create( const aServer: TServerSocket; const aClientTimeout: Longword);
577{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200578begin
579 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +0100580 FServer := aServer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200581
582{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100583 FClientTimeout := aClientTimeout;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200584{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +0100585 FServer.RecvTimeout := aClientTimeout;
586 FServer.SendTimeout := aClientTimeout;
587{$ENDIF}
588end;
589
590
591{$IFDEF OLD_SOCKETS}
592constructor TServerSocketImpl.Create( const aPort: Integer; const aClientTimeout: Integer; const aUseBufferedSockets: Boolean);
593{$ELSE}
594constructor TServerSocketImpl.Create( const aPort: Integer; const aClientTimeout: Longword; const aUseBufferedSockets: Boolean);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200595{$ENDIF}
596begin
597 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +0100598
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200599{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100600 FPort := aPort;
601 FClientTimeout := aClientTimeout;
602
603 FOwnsServer := True;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200604 FServer := TTcpServer.Create( nil );
Jens Geyerd5436f52014-10-03 19:50:38 +0200605 FServer.BlockMode := bmBlocking;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200606 {$IF CompilerVersion >= 21.0}
Jens Geyerd5436f52014-10-03 19:50:38 +0200607 FServer.LocalPort := AnsiString( IntToStr( FPort));
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200608 {$ELSE}
Jens Geyerd5436f52014-10-03 19:50:38 +0200609 FServer.LocalPort := IntToStr( FPort);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200610 {$IFEND}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200611{$ELSE}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200612 FOwnsServer := True;
Jens Geyered994552019-11-09 23:24:52 +0100613 FServer := TServerSocket.Create(aPort, aClientTimeout, aClientTimeout);
614{$ENDIF}
615
616 FUseBufferedSocket := aUseBufferedSockets;
Jens Geyerd5436f52014-10-03 19:50:38 +0200617end;
618
619destructor TServerSocketImpl.Destroy;
620begin
621 if FOwnsServer then begin
622 FServer.Free;
623 FServer := nil;
624 end;
625 inherited;
626end;
627
628function TServerSocketImpl.Accept( const fnAccepting: TProc): ITransport;
629var
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200630{$IFDEF OLD_SOCKETS}
631 client : TCustomIpClient;
632{$ELSE}
633 client: TSocket;
634{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200635 trans : IStreamTransport;
636begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100637 if FServer = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200638 raise TTransportExceptionNotOpen.Create('No underlying server socket.');
Jens Geyerd5436f52014-10-03 19:50:38 +0200639 end;
640
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200641{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200642 client := nil;
643 try
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200644 client := TCustomIpClient.Create(nil);
Jens Geyerd5436f52014-10-03 19:50:38 +0200645
646 if Assigned(fnAccepting)
647 then fnAccepting();
648
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100649 if not FServer.Accept( client) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200650 client.Free;
651 Result := nil;
652 Exit;
653 end;
654
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100655 if client = nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200656 Result := nil;
657 Exit;
658 end;
659
660 trans := TSocketImpl.Create( client, TRUE, FClientTimeout);
661 client := nil; // trans owns it now
662
663 if FUseBufferedSocket
664 then result := TBufferedTransportImpl.Create( trans)
665 else result := trans;
666
667 except
668 on E: Exception do begin
669 client.Free;
Jens Geyere0e32402016-04-20 21:50:48 +0200670 raise TTransportExceptionUnknown.Create(E.ToString);
Jens Geyerd5436f52014-10-03 19:50:38 +0200671 end;
672 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200673{$ELSE}
674 if Assigned(fnAccepting) then
675 fnAccepting();
676
677 client := FServer.Accept;
678 try
Jens Geyered994552019-11-09 23:24:52 +0100679 trans := TSocketImpl.Create(client, MaxMessageSize, True);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200680 client := nil;
681
682 if FUseBufferedSocket then
683 Result := TBufferedTransportImpl.Create(trans)
684 else
685 Result := trans;
686 except
687 client.Free;
688 raise;
689 end;
690{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200691end;
692
693procedure TServerSocketImpl.Listen;
694begin
695 if FServer <> nil then
696 begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200697{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200698 try
699 FServer.Active := True;
700 except
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200701 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200702 do raise TTransportExceptionUnknown.Create('Could not accept on listening socket: ' + E.Message);
Jens Geyerd5436f52014-10-03 19:50:38 +0200703 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200704{$ELSE}
705 FServer.Listen;
706{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200707 end;
708end;
709
710procedure TServerSocketImpl.Close;
711begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200712 if FServer <> nil then
713{$IFDEF OLD_SOCKETS}
714 try
715 FServer.Active := False;
716 except
717 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200718 do raise TTransportExceptionUnknown.Create('Error on closing socket : ' + E.Message);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200719 end;
720{$ELSE}
721 FServer.Close;
722{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200723end;
724
725{ TSocket }
726
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200727{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100728constructor TSocketImpl.Create( const aClient : TCustomIpClient; const aOwnsClient : Boolean; const aTimeout: Integer);
729{$ELSE}
730constructor TSocketImpl.Create(const aClient: TSocket; const aOwnsClient: Boolean);
731{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200732var stream : IThriftStream;
733begin
Jens Geyered994552019-11-09 23:24:52 +0100734 FClient := aClient;
Jens Geyerd5436f52014-10-03 19:50:38 +0200735 FOwnsClient := aOwnsClient;
Jens Geyered994552019-11-09 23:24:52 +0100736
737{$IFDEF OLD_SOCKETS}
738 FTimeout := aTimeout;
739{$ELSE}
740 FTimeout := aClient.RecvTimeout;
741{$ENDIF}
742
Jens Geyerd5436f52014-10-03 19:50:38 +0200743 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
744 inherited Create( stream, stream);
745end;
746
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200747{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +0100748constructor TSocketImpl.Create(const aHost: string; const aPort, aTimeout: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200749{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +0100750constructor TSocketImpl.Create(const aHost: string; const aPort : Integer; const aTimeout: Longword);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200751{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200752begin
753 inherited Create(nil,nil);
Jens Geyered994552019-11-09 23:24:52 +0100754 FHost := aHost;
755 FPort := aPort;
756 FTimeout := aTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200757 InitSocket;
758end;
759
760destructor TSocketImpl.Destroy;
761begin
762 if FOwnsClient
763 then FreeAndNil( FClient);
764 inherited;
765end;
766
767procedure TSocketImpl.Close;
768begin
769 inherited Close;
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200770
771 FInputStream := nil;
772 FOutputStream := nil;
773
Jens Geyerd5436f52014-10-03 19:50:38 +0200774 if FOwnsClient
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200775 then FreeAndNil( FClient)
776 else FClient := nil;
Jens Geyerd5436f52014-10-03 19:50:38 +0200777end;
778
779function TSocketImpl.GetIsOpen: Boolean;
780begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200781{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200782 Result := (FClient <> nil) and FClient.Connected;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200783{$ELSE}
784 Result := (FClient <> nil) and FClient.IsOpen
785{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200786end;
787
788procedure TSocketImpl.InitSocket;
789var
790 stream : IThriftStream;
791begin
792 if FOwnsClient
793 then FreeAndNil( FClient)
794 else FClient := nil;
795
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200796{$IFDEF OLD_SOCKETS}
797 FClient := TTcpClient.Create( nil);
798{$ELSE}
799 FClient := TSocket.Create(FHost, FPort);
800{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200801 FOwnsClient := True;
802
803 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
804 FInputStream := stream;
805 FOutputStream := stream;
806end;
807
808procedure TSocketImpl.Open;
809begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100810 if IsOpen then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200811 raise TTransportExceptionAlreadyOpen.Create('Socket already connected');
Jens Geyerd5436f52014-10-03 19:50:38 +0200812 end;
813
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100814 if FHost = '' then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200815 raise TTransportExceptionNotOpen.Create('Cannot open null host');
Jens Geyerd5436f52014-10-03 19:50:38 +0200816 end;
817
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100818 if Port <= 0 then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200819 raise TTransportExceptionNotOpen.Create('Cannot open without port');
Jens Geyerd5436f52014-10-03 19:50:38 +0200820 end;
821
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100822 if FClient = nil
823 then InitSocket;
Jens Geyerd5436f52014-10-03 19:50:38 +0200824
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200825{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200826 FClient.RemoteHost := TSocketHost( Host);
827 FClient.RemotePort := TSocketPort( IntToStr( Port));
828 FClient.Connect;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200829{$ELSE}
830 FClient.Open;
831{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200832
833 FInputStream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
834 FOutputStream := FInputStream;
835end;
836
837{ TBufferedStream }
838
839procedure TBufferedStreamImpl.Close;
840begin
841 Flush;
842 FStream := nil;
843
844 FReadBuffer.Free;
845 FReadBuffer := nil;
846
847 FWriteBuffer.Free;
848 FWriteBuffer := nil;
849end;
850
Jens Geyered994552019-11-09 23:24:52 +0100851constructor TBufferedStreamImpl.Create( const aStream: IThriftStream; const aBufSize : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200852begin
853 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +0100854 FStream := aStream;
855 FBufSize := aBufSize;
Jens Geyerd5436f52014-10-03 19:50:38 +0200856 FReadBuffer := TMemoryStream.Create;
857 FWriteBuffer := TMemoryStream.Create;
858end;
859
860destructor TBufferedStreamImpl.Destroy;
861begin
862 Close;
863 inherited;
864end;
865
866procedure TBufferedStreamImpl.Flush;
867var
868 buf : TBytes;
869 len : Integer;
870begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200871 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200872 len := FWriteBuffer.Size;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200873 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200874 SetLength( buf, len );
875 FWriteBuffer.Position := 0;
876 FWriteBuffer.Read( Pointer(@buf[0])^, len );
877 FStream.Write( buf, 0, len );
878 end;
879 FWriteBuffer.Clear;
880 end;
881end;
882
883function TBufferedStreamImpl.IsOpen: Boolean;
884begin
885 Result := (FWriteBuffer <> nil)
886 and (FReadBuffer <> nil)
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200887 and (FStream <> nil)
888 and FStream.IsOpen;
Jens Geyerd5436f52014-10-03 19:50:38 +0200889end;
890
891procedure TBufferedStreamImpl.Open;
892begin
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200893 FStream.Open;
Jens Geyerd5436f52014-10-03 19:50:38 +0200894end;
895
Jens Geyer17c3ad92017-09-05 20:31:27 +0200896function TBufferedStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200897var
898 nRead : Integer;
899 tempbuf : TBytes;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100900 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200901begin
902 inherited;
903 Result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100904
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200905 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200906 while count > 0 do begin
907
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200908 if FReadBuffer.Position >= FReadBuffer.Size then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200909 FReadBuffer.Clear;
910 SetLength( tempbuf, FBufSize);
911 nRead := FStream.Read( tempbuf, 0, FBufSize );
912 if nRead = 0 then Break; // avoid infinite loop
913
914 FReadBuffer.WriteBuffer( Pointer(@tempbuf[0])^, nRead );
915 FReadBuffer.Position := 0;
916 end;
917
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200918 if FReadBuffer.Position < FReadBuffer.Size then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100919 nRead := Min( FReadBuffer.Size - FReadBuffer.Position, count);
920 pTmp := pBuf;
921 Inc( pTmp, offset);
922 Inc( Result, FReadBuffer.Read( pTmp^, nRead));
Jens Geyerd5436f52014-10-03 19:50:38 +0200923 Dec( count, nRead);
924 Inc( offset, nRead);
925 end;
926 end;
927 end;
928end;
929
Jens Geyered994552019-11-09 23:24:52 +0100930
Jens Geyerd5436f52014-10-03 19:50:38 +0200931function TBufferedStreamImpl.ToArray: TBytes;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200932var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200933begin
934 len := 0;
935
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200936 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200937 len := FReadBuffer.Size;
938 end;
939
940 SetLength( Result, len);
941
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200942 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200943 FReadBuffer.Position := 0;
944 FReadBuffer.Read( Pointer(@Result[0])^, len );
945 end;
946end;
947
Jens Geyer17c3ad92017-09-05 20:31:27 +0200948procedure TBufferedStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +0100949var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200950begin
951 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200952 if count > 0 then begin
953 if IsOpen then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100954 pTmp := pBuf;
955 Inc( pTmp, offset);
956 FWriteBuffer.Write( pTmp^, count );
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200957 if FWriteBuffer.Size > FBufSize then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200958 Flush;
959 end;
960 end;
961 end;
962end;
963
964{ TStreamTransportImpl }
965
Jens Geyered994552019-11-09 23:24:52 +0100966constructor TStreamTransportImpl.Create( const aInputStream, aOutputStream : IThriftStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200967begin
968 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +0100969 FInputStream := aInputStream;
970 FOutputStream := aOutputStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200971end;
972
973destructor TStreamTransportImpl.Destroy;
974begin
975 FInputStream := nil;
976 FOutputStream := nil;
977 inherited;
978end;
979
Jens Geyer20e727e2018-06-22 22:39:57 +0200980procedure TStreamTransportImpl.Close;
981begin
982 FInputStream := nil;
983 FOutputStream := nil;
984end;
985
Jens Geyerd5436f52014-10-03 19:50:38 +0200986procedure TStreamTransportImpl.Flush;
987begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100988 if FOutputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200989 raise TTransportExceptionNotOpen.Create('Cannot flush null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +0200990 end;
991
992 FOutputStream.Flush;
993end;
994
995function TStreamTransportImpl.GetInputStream: IThriftStream;
996begin
997 Result := FInputStream;
998end;
999
1000function TStreamTransportImpl.GetIsOpen: Boolean;
1001begin
1002 Result := True;
1003end;
1004
1005function TStreamTransportImpl.GetOutputStream: IThriftStream;
1006begin
Jens Geyer02fbe0e2018-03-19 17:35:44 +01001007 Result := FOutputStream;
Jens Geyerd5436f52014-10-03 19:50:38 +02001008end;
1009
1010procedure TStreamTransportImpl.Open;
1011begin
Jens Geyer2646bd62019-11-09 23:24:52 +01001012 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +02001013end;
1014
Jens Geyer17c3ad92017-09-05 20:31:27 +02001015function TStreamTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001016begin
Jens Geyered994552019-11-09 23:24:52 +01001017 if FInputStream = nil
1018 then raise TTransportExceptionNotOpen.Create('Cannot read from null inputstream' );
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001019
Jens Geyer17c3ad92017-09-05 20:31:27 +02001020 Result := FInputStream.Read( pBuf,buflen, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001021end;
1022
Jens Geyer17c3ad92017-09-05 20:31:27 +02001023procedure TStreamTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001024begin
Jens Geyered994552019-11-09 23:24:52 +01001025 if FOutputStream = nil
1026 then raise TTransportExceptionNotOpen.Create('Cannot write to null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001027
Jens Geyer17c3ad92017-09-05 20:31:27 +02001028 FOutputStream.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001029end;
1030
Jens Geyered994552019-11-09 23:24:52 +01001031
Jens Geyerd5436f52014-10-03 19:50:38 +02001032{ TBufferedTransportImpl }
1033
Jens Geyered994552019-11-09 23:24:52 +01001034constructor TBufferedTransportImpl.Create( const aTransport : IStreamTransport; const aBufSize: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001035begin
Jens Geyered994552019-11-09 23:24:52 +01001036 ASSERT( aTransport <> nil);
Jens Geyerd5436f52014-10-03 19:50:38 +02001037 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +01001038 FTransport := aTransport;
1039 FBufSize := aBufSize;
Jens Geyerd5436f52014-10-03 19:50:38 +02001040 InitBuffers;
1041end;
1042
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001043procedure TBufferedTransportImpl.Close;
1044begin
1045 FTransport.Close;
1046 FInputBuffer := nil;
Jens Geyered994552019-11-09 23:24:52 +01001047 FOutputBuffer := nil;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001048end;
1049
Jens Geyerd5436f52014-10-03 19:50:38 +02001050procedure TBufferedTransportImpl.Flush;
1051begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001052 if FOutputBuffer <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001053 FOutputBuffer.Flush;
1054 end;
1055end;
1056
1057function TBufferedTransportImpl.GetIsOpen: Boolean;
1058begin
1059 Result := FTransport.IsOpen;
1060end;
1061
1062function TBufferedTransportImpl.GetUnderlyingTransport: ITransport;
1063begin
1064 Result := FTransport;
1065end;
1066
1067procedure TBufferedTransportImpl.InitBuffers;
1068begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001069 if FTransport.InputStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001070 FInputBuffer := TBufferedStreamImpl.Create( FTransport.InputStream, FBufSize );
1071 end;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001072 if FTransport.OutputStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001073 FOutputBuffer := TBufferedStreamImpl.Create( FTransport.OutputStream, FBufSize );
1074 end;
1075end;
1076
1077procedure TBufferedTransportImpl.Open;
1078begin
Jens Geyera0cf38e2018-04-04 17:31:52 +02001079 FTransport.Open;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001080 InitBuffers; // we need to get the buffers to match FTransport substreams again
Jens Geyerd5436f52014-10-03 19:50:38 +02001081end;
1082
Jens Geyer17c3ad92017-09-05 20:31:27 +02001083function TBufferedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001084begin
Jens Geyered994552019-11-09 23:24:52 +01001085 if FInputBuffer <> nil
1086 then Result := FInputBuffer.Read( pBuf,buflen, off, len)
1087 else Result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +02001088end;
1089
Jens Geyer17c3ad92017-09-05 20:31:27 +02001090procedure TBufferedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001091begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001092 if FOutputBuffer <> nil then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001093 FOutputBuffer.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001094 end;
1095end;
1096
Jens Geyered994552019-11-09 23:24:52 +01001097{ TBufferedTransportImpl.TFactory }
Jens Geyerd5436f52014-10-03 19:50:38 +02001098
Jens Geyered994552019-11-09 23:24:52 +01001099function TBufferedTransportImpl.TFactory.GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +02001100begin
Jens Geyered994552019-11-09 23:24:52 +01001101 Result := TFramedTransportImpl.Create( aTransport);
Jens Geyerd5436f52014-10-03 19:50:38 +02001102end;
1103
Jens Geyered994552019-11-09 23:24:52 +01001104
1105{ TFramedTransportImpl }
1106
1107constructor TFramedTransportImpl.Create( const aTransport: ITransport);
Jens Geyerd5436f52014-10-03 19:50:38 +02001108begin
Jens Geyered994552019-11-09 23:24:52 +01001109 ASSERT( aTransport <> nil);
Jens Geyerd5436f52014-10-03 19:50:38 +02001110 inherited Create;
Jens Geyer2646bd62019-11-09 23:24:52 +01001111
1112 InitMaxFrameSize;
Jens Geyerd5436f52014-10-03 19:50:38 +02001113 InitWriteBuffer;
Jens Geyered994552019-11-09 23:24:52 +01001114 FTransport := aTransport;
Jens Geyerd5436f52014-10-03 19:50:38 +02001115end;
1116
1117destructor TFramedTransportImpl.Destroy;
1118begin
1119 FWriteBuffer.Free;
1120 FReadBuffer.Free;
1121 inherited;
1122end;
1123
Jens Geyer2646bd62019-11-09 23:24:52 +01001124procedure TFramedTransportImpl.InitMaxFrameSize;
1125begin
1126 FMaxFrameSize := DEFAULT_MAX_LENGTH;
1127end;
1128
1129procedure TFramedTransportImpl.Close;
1130begin
1131 FTransport.Close;
1132end;
1133
Jens Geyerd5436f52014-10-03 19:50:38 +02001134procedure TFramedTransportImpl.Flush;
1135var
1136 buf : TBytes;
1137 len : Integer;
1138 data_len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001139begin
1140 len := FWriteBuffer.Size;
1141 SetLength( buf, len);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001142 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001143 System.Move( FWriteBuffer.Memory^, buf[0], len );
1144 end;
1145
Jens Geyer2646bd62019-11-09 23:24:52 +01001146 data_len := len - SizeOf(TFramedHeader);
Jens Geyer30ed90e2016-03-10 20:12:49 +01001147 if (data_len < 0) then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001148 raise TTransportExceptionUnknown.Create('TFramedTransport.Flush: data_len < 0' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001149 end;
1150
1151 InitWriteBuffer;
1152
1153 buf[0] := Byte($FF and (data_len shr 24));
1154 buf[1] := Byte($FF and (data_len shr 16));
1155 buf[2] := Byte($FF and (data_len shr 8));
1156 buf[3] := Byte($FF and data_len);
1157
1158 FTransport.Write( buf, 0, len );
1159 FTransport.Flush;
1160end;
1161
1162function TFramedTransportImpl.GetIsOpen: Boolean;
1163begin
1164 Result := FTransport.IsOpen;
1165end;
1166
1167type
1168 TAccessMemoryStream = class(TMemoryStream)
1169 end;
1170
1171procedure TFramedTransportImpl.InitWriteBuffer;
Jens Geyer2646bd62019-11-09 23:24:52 +01001172const DUMMY_HEADER : TFramedHeader = 0;
Jens Geyerd5436f52014-10-03 19:50:38 +02001173begin
1174 FWriteBuffer.Free;
1175 FWriteBuffer := TMemoryStream.Create;
1176 TAccessMemoryStream(FWriteBuffer).Capacity := 1024;
Jens Geyer2646bd62019-11-09 23:24:52 +01001177 FWriteBuffer.Write( DUMMY_HEADER, SizeOf(DUMMY_HEADER));
Jens Geyerd5436f52014-10-03 19:50:38 +02001178end;
1179
1180procedure TFramedTransportImpl.Open;
1181begin
1182 FTransport.Open;
1183end;
1184
Jens Geyer17c3ad92017-09-05 20:31:27 +02001185function TFramedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001186var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001187begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001188 if len > (buflen-off)
1189 then len := buflen-off;
1190
Jens Geyer5089b0a2018-02-01 22:37:18 +01001191 pTmp := pBuf;
1192 Inc( pTmp, off);
1193
Jens Geyer17c3ad92017-09-05 20:31:27 +02001194 if (FReadBuffer <> nil) and (len > 0) then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001195 result := FReadBuffer.Read( pTmp^, len);
Jens Geyered994552019-11-09 23:24:52 +01001196 if result > 0 then Exit;
Jens Geyerd5436f52014-10-03 19:50:38 +02001197 end;
1198
1199 ReadFrame;
1200 if len > 0
Jens Geyer5089b0a2018-02-01 22:37:18 +01001201 then Result := FReadBuffer.Read( pTmp^, len)
Jens Geyerd5436f52014-10-03 19:50:38 +02001202 else Result := 0;
1203end;
1204
1205procedure TFramedTransportImpl.ReadFrame;
1206var
Jens Geyer2646bd62019-11-09 23:24:52 +01001207 i32rd : packed array[0..SizeOf(TFramedHeader)-1] of Byte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001208 size : Integer;
1209 buff : TBytes;
1210begin
Jens Geyer2646bd62019-11-09 23:24:52 +01001211 FTransport.ReadAll( @i32rd[0], SizeOf(i32rd), 0, SizeOf(i32rd));
Jens Geyerd5436f52014-10-03 19:50:38 +02001212 size :=
1213 ((i32rd[0] and $FF) shl 24) or
1214 ((i32rd[1] and $FF) shl 16) or
1215 ((i32rd[2] and $FF) shl 8) or
1216 (i32rd[3] and $FF);
Jens Geyer2646bd62019-11-09 23:24:52 +01001217
1218 if size < 0 then begin
1219 Close();
1220 raise TTransportExceptionCorruptedData.Create('Read a negative frame size ('+IntToStr(size)+')');
1221 end;
1222
1223 if size > FMaxFrameSize then begin
1224 Close();
1225 raise TTransportExceptionCorruptedData.Create('Frame size ('+IntToStr(size)+') larger than allowed maximum ('+IntToStr(FMaxFrameSize)+')');
1226 end;
1227
Jens Geyerd5436f52014-10-03 19:50:38 +02001228 SetLength( buff, size );
1229 FTransport.ReadAll( buff, 0, size );
Jens Geyered994552019-11-09 23:24:52 +01001230
1231 FreeAndNil( FReadBuffer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001232 FReadBuffer := TMemoryStream.Create;
Jens Geyera76e6c72017-09-08 21:03:30 +02001233 if Length(buff) > 0
1234 then FReadBuffer.Write( Pointer(@buff[0])^, size );
Jens Geyerd5436f52014-10-03 19:50:38 +02001235 FReadBuffer.Position := 0;
1236end;
1237
Jens Geyer17c3ad92017-09-05 20:31:27 +02001238procedure TFramedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001239var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001240begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001241 if len > 0 then begin
1242 pTmp := pBuf;
1243 Inc( pTmp, off);
1244
1245 FWriteBuffer.Write( pTmp^, len );
1246 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001247end;
1248
Jens Geyered994552019-11-09 23:24:52 +01001249
Jens Geyerd5436f52014-10-03 19:50:38 +02001250{ TFramedTransport.TFactory }
1251
Jens Geyered994552019-11-09 23:24:52 +01001252function TFramedTransportImpl.TFactory.GetTransport( const aTransport: ITransport): ITransport;
Jens Geyerd5436f52014-10-03 19:50:38 +02001253begin
Jens Geyered994552019-11-09 23:24:52 +01001254 Result := TFramedTransportImpl.Create( aTransport);
Jens Geyerd5436f52014-10-03 19:50:38 +02001255end;
1256
1257{ TTcpSocketStreamImpl }
1258
1259procedure TTcpSocketStreamImpl.Close;
1260begin
1261 FTcpClient.Close;
1262end;
1263
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001264{$IFDEF OLD_SOCKETS}
Jens Geyered994552019-11-09 23:24:52 +01001265constructor TTcpSocketStreamImpl.Create( const aTcpClient: TCustomIpClient; const aTimeout : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001266begin
1267 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +01001268 FTcpClient := aTcpClient;
Jens Geyerd5436f52014-10-03 19:50:38 +02001269 FTimeout := aTimeout;
1270end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001271{$ELSE}
Jens Geyered994552019-11-09 23:24:52 +01001272constructor TTcpSocketStreamImpl.Create( const aTcpClient: TSocket; const aTimeout : Longword);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001273begin
1274 inherited Create;
Jens Geyered994552019-11-09 23:24:52 +01001275 FTcpClient := aTcpClient;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001276 if aTimeout = 0 then
1277 FTcpClient.RecvTimeout := SLEEP_TIME
1278 else
1279 FTcpClient.RecvTimeout := aTimeout;
1280 FTcpClient.SendTimeout := aTimeout;
1281end;
1282{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001283
1284procedure TTcpSocketStreamImpl.Flush;
1285begin
1286
1287end;
1288
1289function TTcpSocketStreamImpl.IsOpen: Boolean;
1290begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001291{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001292 Result := FTcpClient.Active;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001293{$ELSE}
1294 Result := FTcpClient.IsOpen;
1295{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001296end;
1297
1298procedure TTcpSocketStreamImpl.Open;
1299begin
1300 FTcpClient.Open;
1301end;
1302
1303
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001304{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001305function TTcpSocketStreamImpl.Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
1306 TimeOut: Integer; var wsaError : Integer): Integer;
1307var
1308 ReadFds: TFDset;
1309 ReadFdsptr: PFDset;
1310 WriteFds: TFDset;
1311 WriteFdsptr: PFDset;
1312 ExceptFds: TFDset;
1313 ExceptFdsptr: PFDset;
1314 tv: timeval;
1315 Timeptr: PTimeval;
1316 socket : TSocket;
1317begin
1318 if not FTcpClient.Active then begin
1319 wsaError := WSAEINVAL;
1320 Exit( SOCKET_ERROR);
1321 end;
1322
1323 socket := FTcpClient.Handle;
1324
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001325 if Assigned(ReadReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001326 ReadFdsptr := @ReadFds;
1327 FD_ZERO(ReadFds);
1328 FD_SET(socket, ReadFds);
1329 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001330 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001331 ReadFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001332 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001333
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001334 if Assigned(WriteReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001335 WriteFdsptr := @WriteFds;
1336 FD_ZERO(WriteFds);
1337 FD_SET(socket, WriteFds);
1338 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001339 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001340 WriteFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001341 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001342
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001343 if Assigned(ExceptFlag) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001344 ExceptFdsptr := @ExceptFds;
1345 FD_ZERO(ExceptFds);
1346 FD_SET(socket, ExceptFds);
1347 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001348 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001349 ExceptFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001350 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001351
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001352 if TimeOut >= 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001353 tv.tv_sec := TimeOut div 1000;
1354 tv.tv_usec := 1000 * (TimeOut mod 1000);
1355 Timeptr := @tv;
1356 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001357 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001358 Timeptr := nil; // wait forever
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001359 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001360
1361 wsaError := 0;
1362 try
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001363 {$IFDEF MSWINDOWS}
1364 {$IFDEF OLD_UNIT_NAMES}
1365 result := WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1366 {$ELSE}
1367 result := Winapi.WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1368 {$ENDIF}
1369 {$ENDIF}
1370 {$IFDEF LINUX}
1371 result := Libc.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1372 {$ENDIF}
1373
Jens Geyerd5436f52014-10-03 19:50:38 +02001374 if result = SOCKET_ERROR
1375 then wsaError := WSAGetLastError;
1376
1377 except
1378 result := SOCKET_ERROR;
1379 end;
1380
1381 if Assigned(ReadReady) then
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001382 ReadReady^ := FD_ISSET(socket, ReadFds);
1383
Jens Geyerd5436f52014-10-03 19:50:38 +02001384 if Assigned(WriteReady) then
1385 WriteReady^ := FD_ISSET(socket, WriteFds);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001386
Jens Geyerd5436f52014-10-03 19:50:38 +02001387 if Assigned(ExceptFlag) then
1388 ExceptFlag^ := FD_ISSET(socket, ExceptFds);
1389end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001390{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001391
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001392{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001393function TTcpSocketStreamImpl.WaitForData( TimeOut : Integer; pBuf : Pointer;
1394 DesiredBytes : Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001395 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001396var bCanRead, bError : Boolean;
1397 retval : Integer;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001398const
1399 MSG_PEEK = {$IFDEF OLD_UNIT_NAMES} WinSock.MSG_PEEK {$ELSE} Winapi.WinSock.MSG_PEEK {$ENDIF};
Jens Geyerd5436f52014-10-03 19:50:38 +02001400begin
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001401 bytesReady := 0;
1402
Jens Geyerd5436f52014-10-03 19:50:38 +02001403 // The select function returns the total number of socket handles that are ready
1404 // and contained in the fd_set structures, zero if the time limit expired,
1405 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1406 // WSAGetLastError can be used to retrieve a specific error code.
1407 retval := Self.Select( @bCanRead, nil, @bError, TimeOut, wsaError);
1408 if retval = SOCKET_ERROR
1409 then Exit( TWaitForData.wfd_Error);
1410 if (retval = 0) or not bCanRead
1411 then Exit( TWaitForData.wfd_Timeout);
1412
1413 // recv() returns the number of bytes received, or -1 if an error occurred.
1414 // The return value will be 0 when the peer has performed an orderly shutdown.
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001415
1416 retval := recv( FTcpClient.Handle, pBuf^, DesiredBytes, MSG_PEEK);
Jens Geyerd5436f52014-10-03 19:50:38 +02001417 if retval <= 0
1418 then Exit( TWaitForData.wfd_Error);
1419
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001420 // at least we have some data
1421 bytesReady := Min( retval, DesiredBytes);
1422 result := TWaitForData.wfd_HaveData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001423end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001424{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001425
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001426{$IFDEF OLD_SOCKETS}
Jens Geyer17c3ad92017-09-05 20:31:27 +02001427function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001428// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001429var wfd : TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001430 wsaError,
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001431 msecs : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001432 nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001433 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001434begin
1435 inherited;
1436
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001437 if FTimeout > 0
1438 then msecs := FTimeout
1439 else msecs := DEFAULT_THRIFT_TIMEOUT;
1440
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001441 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001442 pTmp := pBuf;
1443 Inc( pTmp, offset);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001444 while count > 0 do begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001445
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001446 while TRUE do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001447 wfd := WaitForData( msecs, pTmp, count, wsaError, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001448 case wfd of
Jens Geyer65b17462016-03-09 00:07:46 +01001449 TWaitForData.wfd_Error : Exit;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001450 TWaitForData.wfd_HaveData : Break;
1451 TWaitForData.wfd_Timeout : begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001452 if (FTimeout = 0)
1453 then Exit
1454 else begin
Jens Geyere0e32402016-04-20 21:50:48 +02001455 raise TTransportExceptionTimedOut.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001456
1457 end;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001458 end;
1459 else
1460 ASSERT( FALSE);
Jens Geyerd5436f52014-10-03 19:50:38 +02001461 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001462 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001463
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001464 // reduce the timeout once we got data
1465 if FTimeout > 0
1466 then msecs := FTimeout div 10
1467 else msecs := DEFAULT_THRIFT_TIMEOUT div 10;
1468 msecs := Max( msecs, 200);
1469
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001470 ASSERT( nBytes <= count);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001471 nBytes := FTcpClient.ReceiveBuf( pTmp^, nBytes);
1472 Inc( pTmp, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001473 Dec( count, nBytes);
1474 Inc( result, nBytes);
1475 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001476end;
1477
1478function TTcpSocketStreamImpl.ToArray: TBytes;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001479// old sockets version
1480var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001481begin
1482 len := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001483 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001484 len := FTcpClient.BytesReceived;
1485 end;
1486
1487 SetLength( Result, len );
1488
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001489 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001490 FTcpClient.ReceiveBuf( Pointer(@Result[0])^, len);
1491 end;
1492end;
1493
Jens Geyer17c3ad92017-09-05 20:31:27 +02001494procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001495// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001496var bCanWrite, bError : Boolean;
1497 retval, wsaError : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001498 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001499begin
1500 inherited;
1501
1502 if not FTcpClient.Active
Jens Geyere0e32402016-04-20 21:50:48 +02001503 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerd5436f52014-10-03 19:50:38 +02001504
1505 // The select function returns the total number of socket handles that are ready
1506 // and contained in the fd_set structures, zero if the time limit expired,
1507 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1508 // WSAGetLastError can be used to retrieve a specific error code.
1509 retval := Self.Select( nil, @bCanWrite, @bError, FTimeOut, wsaError);
1510 if retval = SOCKET_ERROR
Jens Geyere0e32402016-04-20 21:50:48 +02001511 then raise TTransportExceptionUnknown.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001512
Jens Geyerd5436f52014-10-03 19:50:38 +02001513 if (retval = 0)
Jens Geyere0e32402016-04-20 21:50:48 +02001514 then raise TTransportExceptionTimedOut.Create('timed out');
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001515
Jens Geyerd5436f52014-10-03 19:50:38 +02001516 if bError or not bCanWrite
Jens Geyere0e32402016-04-20 21:50:48 +02001517 then raise TTransportExceptionUnknown.Create('unknown error');
Jens Geyerd5436f52014-10-03 19:50:38 +02001518
Jens Geyer5089b0a2018-02-01 22:37:18 +01001519 pTmp := pBuf;
1520 Inc( pTmp, offset);
1521 FTcpClient.SendBuf( pTmp^, count);
Jens Geyerd5436f52014-10-03 19:50:38 +02001522end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001523
1524{$ELSE}
1525
Jens Geyer17c3ad92017-09-05 20:31:27 +02001526function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001527// new sockets version
1528var nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001529 pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001530begin
1531 inherited;
1532
1533 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001534 pTmp := pBuf;
1535 Inc( pTmp, offset);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001536 while count > 0 do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001537 nBytes := FTcpClient.Read( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001538 if nBytes = 0 then Exit;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001539 Inc( pTmp, nBytes);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001540 Dec( count, nBytes);
1541 Inc( result, nBytes);
1542 end;
1543end;
1544
1545function TTcpSocketStreamImpl.ToArray: TBytes;
1546// new sockets version
1547var len : Integer;
1548begin
1549 len := 0;
1550 try
1551 if FTcpClient.Peek then
1552 repeat
1553 SetLength(Result, Length(Result) + 1024);
1554 len := FTcpClient.Read(Result[Length(Result) - 1024], 1024);
1555 until len < 1024;
1556 except
1557 on TTransportException do begin { don't allow default exceptions } end;
1558 else raise;
1559 end;
1560 if len > 0 then
1561 SetLength(Result, Length(Result) - 1024 + len);
1562end;
1563
Jens Geyer17c3ad92017-09-05 20:31:27 +02001564procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001565// new sockets version
Jens Geyer5089b0a2018-02-01 22:37:18 +01001566var pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001567begin
1568 inherited;
1569
1570 if not FTcpClient.IsOpen
Kyle Johnsone363a342016-04-22 19:11:16 -05001571 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001572
Jens Geyer5089b0a2018-02-01 22:37:18 +01001573 pTmp := pBuf;
1574 Inc( pTmp, offset);
1575 FTcpClient.Write( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001576end;
1577
Jens Geyer23d67462015-12-19 11:44:57 +01001578{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001579
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001580
Jens Geyerd5436f52014-10-03 19:50:38 +02001581
1582end.