blob: 3067bcd76e360de7f48eec35d839e48c00b85001 [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)
203 function GetTransport( const ATrans: ITransport): ITransport; virtual;
204 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;
256 public
257 property InputStream : IThriftStream read GetInputStream;
258 property OutputStream : IThriftStream read GetOutputStream;
259
260 procedure Open; override;
261 procedure Close; override;
262 procedure Flush; override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200263 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
264 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200265 constructor Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);
266 destructor Destroy; override;
267 end;
268
269 TBufferedStreamImpl = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100270 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200271 FStream : IThriftStream;
272 FBufSize : Integer;
273 FReadBuffer : TMemoryStream;
274 FWriteBuffer : TMemoryStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100275 strict protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200276 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
277 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200278 procedure Open; override;
279 procedure Close; override;
280 procedure Flush; override;
281 function IsOpen: Boolean; override;
282 function ToArray: TBytes; override;
283 public
284 constructor Create( const AStream: IThriftStream; ABufSize: Integer);
285 destructor Destroy; override;
286 end;
287
288 TServerSocketImpl = class( TServerTransportImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100289 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200290{$IFDEF OLD_SOCKETS}
291 FServer : TTcpServer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200292 FPort : Integer;
293 FClientTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200294{$ELSE}
295 FServer: TServerSocket;
296{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200297 FUseBufferedSocket : Boolean;
298 FOwnsServer : Boolean;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100299 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200300 function Accept( const fnAccepting: TProc) : ITransport; override;
301 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200302{$IFDEF OLD_SOCKETS}
303 constructor Create( const AServer: TTcpServer; AClientTimeout: Integer = 0); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +0200304 constructor Create( APort: Integer; AClientTimeout: Integer = 0; AUseBufferedSockets: Boolean = FALSE); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200305{$ELSE}
306 constructor Create( const AServer: TServerSocket; AClientTimeout: Longword = 0); overload;
307 constructor Create( APort: Integer; AClientTimeout: Longword = 0; AUseBufferedSockets: Boolean = FALSE); overload;
308{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200309 destructor Destroy; override;
310 procedure Listen; override;
311 procedure Close; override;
312 end;
313
314 TBufferedTransportImpl = class( TTransportImpl )
Jens Geyerfad7fd32019-11-09 23:24:52 +0100315 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200316 FInputBuffer : IThriftStream;
317 FOutputBuffer : IThriftStream;
318 FTransport : IStreamTransport;
319 FBufSize : Integer;
320
321 procedure InitBuffers;
322 function GetUnderlyingTransport: ITransport;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100323 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200324 function GetIsOpen: Boolean; override;
325 procedure Flush; override;
326 public
327 procedure Open(); override;
328 procedure Close(); 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 Geyerd5436f52014-10-03 19:50:38 +0200331 constructor Create( const ATransport : IStreamTransport ); overload;
332 constructor Create( const ATransport : IStreamTransport; ABufSize: Integer); overload;
333 property UnderlyingTransport: ITransport read GetUnderlyingTransport;
334 property IsOpen: Boolean read GetIsOpen;
335 end;
336
337 TSocketImpl = class(TStreamTransportImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100338 strict private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200339{$IFDEF OLD_SOCKETS}
340 FClient : TCustomIpClient;
341{$ELSE}
342 FClient: TSocket;
343{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200344 FOwnsClient : Boolean;
345 FHost : string;
346 FPort : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200347{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200348 FTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200349{$ELSE}
350 FTimeout : Longword;
351{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200352
353 procedure InitSocket;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100354 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200355 function GetIsOpen: Boolean; override;
356 public
357 procedure Open; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200358{$IFDEF OLD_SOCKETS}
359 constructor Create( const AClient : TCustomIpClient; aOwnsClient : Boolean; ATimeout: Integer = 0); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +0200360 constructor Create( const AHost: string; APort: Integer; ATimeout: Integer = 0); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200361{$ELSE}
362 constructor Create(const AClient: TSocket; aOwnsClient: Boolean); overload;
363 constructor Create( const AHost: string; APort: Integer; ATimeout: Longword = 0); overload;
364{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200365 destructor Destroy; override;
366 procedure Close; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200367{$IFDEF OLD_SOCKETS}
368 property TcpClient: TCustomIpClient read FClient;
369{$ELSE}
370 property TcpClient: TSocket read FClient;
371{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200372 property Host : string read FHost;
373 property Port: Integer read FPort;
374 end;
375
376 TFramedTransportImpl = class( TTransportImpl)
Jens Geyer2646bd62019-11-09 23:24:52 +0100377 strict protected const
378 DEFAULT_MAX_LENGTH = 16384000; // this value is used by all Thrift libraries
379 strict protected type
380 TFramedHeader = Int32;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100381 strict protected
Jens Geyerd5436f52014-10-03 19:50:38 +0200382 FTransport : ITransport;
383 FWriteBuffer : TMemoryStream;
384 FReadBuffer : TMemoryStream;
Jens Geyer2646bd62019-11-09 23:24:52 +0100385 FMaxFrameSize : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200386
Jens Geyer2646bd62019-11-09 23:24:52 +0100387 procedure InitMaxFrameSize;
Jens Geyerd5436f52014-10-03 19:50:38 +0200388 procedure InitWriteBuffer;
389 procedure ReadFrame;
390 public
391 type
392 TFactory = class( TTransportFactoryImpl )
393 public
394 function GetTransport( const ATrans: ITransport): ITransport; override;
395 end;
396
Jens Geyerd5436f52014-10-03 19:50:38 +0200397 constructor Create; overload;
398 constructor Create( const ATrans: ITransport); overload;
399 destructor Destroy; override;
400
401 procedure Open(); override;
402 function GetIsOpen: Boolean; override;
403
404 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200405 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
406 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200407 procedure Flush; override;
408 end;
409
Jens Geyerd5436f52014-10-03 19:50:38 +0200410
411const
412 DEFAULT_THRIFT_TIMEOUT = 5 * 1000; // ms
Jens Geyer47f63172019-06-06 22:42:58 +0200413 DEFAULT_THRIFT_SECUREPROTOCOLS = [ TSecureProtocol.TLS_1_1, TSecureProtocol.TLS_1_2];
414
Jens Geyerd5436f52014-10-03 19:50:38 +0200415
416
417implementation
418
419{ TTransportImpl }
420
421procedure TTransportImpl.Flush;
422begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200423 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200424end;
425
426function TTransportImpl.Peek: Boolean;
427begin
428 Result := IsOpen;
429end;
430
Jens Geyer17c3ad92017-09-05 20:31:27 +0200431function TTransportImpl.Read(var buf: TBytes; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200432begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200433 if Length(buf) > 0
434 then result := Read( @buf[0], Length(buf), off, len)
435 else result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200436end;
437
438function TTransportImpl.ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;
439begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200440 if Length(buf) > 0
441 then result := ReadAll( @buf[0], Length(buf), off, len)
442 else result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200443end;
444
445procedure TTransportImpl.Write( const buf: TBytes);
446begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200447 if Length(buf) > 0
448 then Write( @buf[0], 0, Length(buf));
Jens Geyer17c3ad92017-09-05 20:31:27 +0200449end;
450
451procedure TTransportImpl.Write( const buf: TBytes; off: Integer; len: Integer);
452begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200453 if Length(buf) > 0
454 then Write( @buf[0], off, len);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200455end;
456
457function TTransportImpl.ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
458var ret : Integer;
459begin
460 result := 0;
461 while result < len do begin
462 ret := Read( pBuf, buflen, off + result, len - result);
463 if ret > 0
464 then Inc( result, ret)
465 else raise TTransportExceptionNotOpen.Create( 'Cannot read, Remote side has closed' );
466 end;
467end;
468
469procedure TTransportImpl.Write( const pBuf : Pointer; len : Integer);
470begin
471 Self.Write( pBuf, 0, len);
Jens Geyerd5436f52014-10-03 19:50:38 +0200472end;
473
Jens Geyerd5436f52014-10-03 19:50:38 +0200474{ TTransportException }
475
Jens Geyere0e32402016-04-20 21:50:48 +0200476constructor TTransportException.HiddenCreate(const Msg: string);
477begin
478 inherited Create(Msg);
479end;
480
481class function TTransportException.Create(AType: TExceptionType): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200482begin
483 //no inherited;
Jens Geyere0e32402016-04-20 21:50:48 +0200484{$WARN SYMBOL_DEPRECATED OFF}
485 Result := Create(AType, '')
486{$WARN SYMBOL_DEPRECATED DEFAULT}
Jens Geyerd5436f52014-10-03 19:50:38 +0200487end;
488
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100489class function TTransportException.Create(aType: TExceptionType; const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200490begin
Jens Geyere0e32402016-04-20 21:50:48 +0200491 case AType of
492 TExceptionType.NotOpen: Result := TTransportExceptionNotOpen.Create(msg);
493 TExceptionType.AlreadyOpen: Result := TTransportExceptionAlreadyOpen.Create(msg);
494 TExceptionType.TimedOut: Result := TTransportExceptionTimedOut.Create(msg);
495 TExceptionType.EndOfFile: Result := TTransportExceptionEndOfFile.Create(msg);
496 TExceptionType.BadArgs: Result := TTransportExceptionBadArgs.Create(msg);
497 TExceptionType.Interrupted: Result := TTransportExceptionInterrupted.Create(msg);
498 else
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100499 ASSERT( TExceptionType.Unknown = aType);
Jens Geyere0e32402016-04-20 21:50:48 +0200500 Result := TTransportExceptionUnknown.Create(msg);
501 end;
Jens Geyerd5436f52014-10-03 19:50:38 +0200502end;
503
Jens Geyere0e32402016-04-20 21:50:48 +0200504class function TTransportException.Create(const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200505begin
Jens Geyere0e32402016-04-20 21:50:48 +0200506 Result := TTransportExceptionUnknown.Create(Msg);
507end;
508
509{ TTransportExceptionSpecialized }
510
511constructor TTransportExceptionSpecialized.Create(const Msg: string);
512begin
513 inherited HiddenCreate(Msg);
Jens Geyerd5436f52014-10-03 19:50:38 +0200514end;
515
Jens Geyer9f11c1e2019-11-09 19:39:20 +0100516{ specialized TTransportExceptions }
517
518class function TTransportExceptionUnknown.GetType: TTransportException.TExceptionType;
519begin
520 result := TExceptionType.Unknown;
521end;
522
523class function TTransportExceptionNotOpen.GetType: TTransportException.TExceptionType;
524begin
525 result := TExceptionType.NotOpen;
526end;
527
528class function TTransportExceptionAlreadyOpen.GetType: TTransportException.TExceptionType;
529begin
530 result := TExceptionType.AlreadyOpen;
531end;
532
533class function TTransportExceptionTimedOut.GetType: TTransportException.TExceptionType;
534begin
535 result := TExceptionType.TimedOut;
536end;
537
538class function TTransportExceptionEndOfFile.GetType: TTransportException.TExceptionType;
539begin
540 result := TExceptionType.EndOfFile;
541end;
542
543class function TTransportExceptionBadArgs.GetType: TTransportException.TExceptionType;
544begin
545 result := TExceptionType.BadArgs;
546end;
547
548class function TTransportExceptionInterrupted.GetType: TTransportException.TExceptionType;
549begin
550 result := TExceptionType.Interrupted;
551end;
552
Jens Geyer2646bd62019-11-09 23:24:52 +0100553class function TTransportExceptionCorruptedData.GetType: TTransportException.TExceptionType;
554begin
555 result := TExceptionType.CorruptedData;
556end;
557
Jens Geyerd5436f52014-10-03 19:50:38 +0200558{ TTransportFactoryImpl }
559
560function TTransportFactoryImpl.GetTransport( const ATrans: ITransport): ITransport;
561begin
562 Result := ATrans;
563end;
564
565{ TServerSocket }
566
Jens Geyer23d67462015-12-19 11:44:57 +0100567{$IFDEF OLD_SOCKETS}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200568constructor TServerSocketImpl.Create( const AServer: TTcpServer; AClientTimeout: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200569begin
570 inherited Create;
571 FServer := AServer;
572 FClientTimeout := AClientTimeout;
573end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200574{$ELSE}
575constructor TServerSocketImpl.Create( const AServer: TServerSocket; AClientTimeout: Longword);
Jens Geyerd5436f52014-10-03 19:50:38 +0200576begin
577 inherited Create;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200578 FServer := AServer;
579 FServer.RecvTimeout := AClientTimeout;
580 FServer.SendTimeout := AClientTimeout;
581end;
582{$ENDIF}
583
584{$IFDEF OLD_SOCKETS}
585constructor TServerSocketImpl.Create(APort, AClientTimeout: Integer; AUseBufferedSockets: Boolean);
586{$ELSE}
587constructor TServerSocketImpl.Create(APort: Integer; AClientTimeout: Longword; AUseBufferedSockets: Boolean);
588{$ENDIF}
589begin
590 inherited Create;
591{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200592 FPort := APort;
593 FClientTimeout := AClientTimeout;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200594 FServer := TTcpServer.Create( nil );
Jens Geyerd5436f52014-10-03 19:50:38 +0200595 FServer.BlockMode := bmBlocking;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200596 {$IF CompilerVersion >= 21.0}
Jens Geyerd5436f52014-10-03 19:50:38 +0200597 FServer.LocalPort := AnsiString( IntToStr( FPort));
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200598 {$ELSE}
Jens Geyerd5436f52014-10-03 19:50:38 +0200599 FServer.LocalPort := IntToStr( FPort);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200600 {$IFEND}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200601{$ELSE}
602 FServer := TServerSocket.Create(APort, AClientTimeout, AClientTimeout);
603{$ENDIF}
604 FUseBufferedSocket := AUseBufferedSockets;
605 FOwnsServer := True;
Jens Geyerd5436f52014-10-03 19:50:38 +0200606end;
607
608destructor TServerSocketImpl.Destroy;
609begin
610 if FOwnsServer then begin
611 FServer.Free;
612 FServer := nil;
613 end;
614 inherited;
615end;
616
617function TServerSocketImpl.Accept( const fnAccepting: TProc): ITransport;
618var
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200619{$IFDEF OLD_SOCKETS}
620 client : TCustomIpClient;
621{$ELSE}
622 client: TSocket;
623{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200624 trans : IStreamTransport;
625begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100626 if FServer = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200627 raise TTransportExceptionNotOpen.Create('No underlying server socket.');
Jens Geyerd5436f52014-10-03 19:50:38 +0200628 end;
629
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200630{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200631 client := nil;
632 try
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200633 client := TCustomIpClient.Create(nil);
Jens Geyerd5436f52014-10-03 19:50:38 +0200634
635 if Assigned(fnAccepting)
636 then fnAccepting();
637
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100638 if not FServer.Accept( client) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200639 client.Free;
640 Result := nil;
641 Exit;
642 end;
643
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100644 if client = nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200645 Result := nil;
646 Exit;
647 end;
648
649 trans := TSocketImpl.Create( client, TRUE, FClientTimeout);
650 client := nil; // trans owns it now
651
652 if FUseBufferedSocket
653 then result := TBufferedTransportImpl.Create( trans)
654 else result := trans;
655
656 except
657 on E: Exception do begin
658 client.Free;
Jens Geyere0e32402016-04-20 21:50:48 +0200659 raise TTransportExceptionUnknown.Create(E.ToString);
Jens Geyerd5436f52014-10-03 19:50:38 +0200660 end;
661 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200662{$ELSE}
663 if Assigned(fnAccepting) then
664 fnAccepting();
665
666 client := FServer.Accept;
667 try
668 trans := TSocketImpl.Create(client, True);
669 client := nil;
670
671 if FUseBufferedSocket then
672 Result := TBufferedTransportImpl.Create(trans)
673 else
674 Result := trans;
675 except
676 client.Free;
677 raise;
678 end;
679{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200680end;
681
682procedure TServerSocketImpl.Listen;
683begin
684 if FServer <> nil then
685 begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200686{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200687 try
688 FServer.Active := True;
689 except
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200690 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200691 do raise TTransportExceptionUnknown.Create('Could not accept on listening socket: ' + E.Message);
Jens Geyerd5436f52014-10-03 19:50:38 +0200692 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200693{$ELSE}
694 FServer.Listen;
695{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200696 end;
697end;
698
699procedure TServerSocketImpl.Close;
700begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200701 if FServer <> nil then
702{$IFDEF OLD_SOCKETS}
703 try
704 FServer.Active := False;
705 except
706 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200707 do raise TTransportExceptionUnknown.Create('Error on closing socket : ' + E.Message);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200708 end;
709{$ELSE}
710 FServer.Close;
711{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200712end;
713
714{ TSocket }
715
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200716{$IFDEF OLD_SOCKETS}
717constructor TSocketImpl.Create( const AClient : TCustomIpClient; aOwnsClient : Boolean; ATimeout: Integer = 0);
Jens Geyerd5436f52014-10-03 19:50:38 +0200718var stream : IThriftStream;
719begin
720 FClient := AClient;
721 FTimeout := ATimeout;
722 FOwnsClient := aOwnsClient;
723 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
724 inherited Create( stream, stream);
725end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200726{$ELSE}
727constructor TSocketImpl.Create(const AClient: TSocket; aOwnsClient: Boolean);
728var stream : IThriftStream;
729begin
730 FClient := AClient;
731 FTimeout := AClient.RecvTimeout;
732 FOwnsClient := aOwnsClient;
733 stream := TTcpSocketStreamImpl.Create(FClient, FTimeout);
734 inherited Create(stream, stream);
735end;
736{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200737
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200738{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200739constructor TSocketImpl.Create(const AHost: string; APort, ATimeout: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200740{$ELSE}
741constructor TSocketImpl.Create(const AHost: string; APort: Integer; ATimeout: Longword);
742{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200743begin
744 inherited Create(nil,nil);
745 FHost := AHost;
746 FPort := APort;
747 FTimeout := ATimeout;
748 InitSocket;
749end;
750
751destructor TSocketImpl.Destroy;
752begin
753 if FOwnsClient
754 then FreeAndNil( FClient);
755 inherited;
756end;
757
758procedure TSocketImpl.Close;
759begin
760 inherited Close;
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200761
762 FInputStream := nil;
763 FOutputStream := nil;
764
Jens Geyerd5436f52014-10-03 19:50:38 +0200765 if FOwnsClient
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200766 then FreeAndNil( FClient)
767 else FClient := nil;
Jens Geyerd5436f52014-10-03 19:50:38 +0200768end;
769
770function TSocketImpl.GetIsOpen: Boolean;
771begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200772{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200773 Result := (FClient <> nil) and FClient.Connected;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200774{$ELSE}
775 Result := (FClient <> nil) and FClient.IsOpen
776{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200777end;
778
779procedure TSocketImpl.InitSocket;
780var
781 stream : IThriftStream;
782begin
783 if FOwnsClient
784 then FreeAndNil( FClient)
785 else FClient := nil;
786
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200787{$IFDEF OLD_SOCKETS}
788 FClient := TTcpClient.Create( nil);
789{$ELSE}
790 FClient := TSocket.Create(FHost, FPort);
791{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200792 FOwnsClient := True;
793
794 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
795 FInputStream := stream;
796 FOutputStream := stream;
797end;
798
799procedure TSocketImpl.Open;
800begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100801 if IsOpen then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200802 raise TTransportExceptionAlreadyOpen.Create('Socket already connected');
Jens Geyerd5436f52014-10-03 19:50:38 +0200803 end;
804
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100805 if FHost = '' then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200806 raise TTransportExceptionNotOpen.Create('Cannot open null host');
Jens Geyerd5436f52014-10-03 19:50:38 +0200807 end;
808
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100809 if Port <= 0 then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200810 raise TTransportExceptionNotOpen.Create('Cannot open without port');
Jens Geyerd5436f52014-10-03 19:50:38 +0200811 end;
812
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100813 if FClient = nil
814 then InitSocket;
Jens Geyerd5436f52014-10-03 19:50:38 +0200815
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200816{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200817 FClient.RemoteHost := TSocketHost( Host);
818 FClient.RemotePort := TSocketPort( IntToStr( Port));
819 FClient.Connect;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200820{$ELSE}
821 FClient.Open;
822{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200823
824 FInputStream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
825 FOutputStream := FInputStream;
826end;
827
828{ TBufferedStream }
829
830procedure TBufferedStreamImpl.Close;
831begin
832 Flush;
833 FStream := nil;
834
835 FReadBuffer.Free;
836 FReadBuffer := nil;
837
838 FWriteBuffer.Free;
839 FWriteBuffer := nil;
840end;
841
842constructor TBufferedStreamImpl.Create( const AStream: IThriftStream; ABufSize: Integer);
843begin
844 inherited Create;
845 FStream := AStream;
846 FBufSize := ABufSize;
847 FReadBuffer := TMemoryStream.Create;
848 FWriteBuffer := TMemoryStream.Create;
849end;
850
851destructor TBufferedStreamImpl.Destroy;
852begin
853 Close;
854 inherited;
855end;
856
857procedure TBufferedStreamImpl.Flush;
858var
859 buf : TBytes;
860 len : Integer;
861begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200862 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200863 len := FWriteBuffer.Size;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200864 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200865 SetLength( buf, len );
866 FWriteBuffer.Position := 0;
867 FWriteBuffer.Read( Pointer(@buf[0])^, len );
868 FStream.Write( buf, 0, len );
869 end;
870 FWriteBuffer.Clear;
871 end;
872end;
873
874function TBufferedStreamImpl.IsOpen: Boolean;
875begin
876 Result := (FWriteBuffer <> nil)
877 and (FReadBuffer <> nil)
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200878 and (FStream <> nil)
879 and FStream.IsOpen;
Jens Geyerd5436f52014-10-03 19:50:38 +0200880end;
881
882procedure TBufferedStreamImpl.Open;
883begin
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200884 FStream.Open;
Jens Geyerd5436f52014-10-03 19:50:38 +0200885end;
886
Jens Geyer17c3ad92017-09-05 20:31:27 +0200887function TBufferedStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200888var
889 nRead : Integer;
890 tempbuf : TBytes;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100891 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200892begin
893 inherited;
894 Result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100895
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200896 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200897 while count > 0 do begin
898
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200899 if FReadBuffer.Position >= FReadBuffer.Size then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200900 FReadBuffer.Clear;
901 SetLength( tempbuf, FBufSize);
902 nRead := FStream.Read( tempbuf, 0, FBufSize );
903 if nRead = 0 then Break; // avoid infinite loop
904
905 FReadBuffer.WriteBuffer( Pointer(@tempbuf[0])^, nRead );
906 FReadBuffer.Position := 0;
907 end;
908
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200909 if FReadBuffer.Position < FReadBuffer.Size then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100910 nRead := Min( FReadBuffer.Size - FReadBuffer.Position, count);
911 pTmp := pBuf;
912 Inc( pTmp, offset);
913 Inc( Result, FReadBuffer.Read( pTmp^, nRead));
Jens Geyerd5436f52014-10-03 19:50:38 +0200914 Dec( count, nRead);
915 Inc( offset, nRead);
916 end;
917 end;
918 end;
919end;
920
921function TBufferedStreamImpl.ToArray: TBytes;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200922var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200923begin
924 len := 0;
925
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200926 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200927 len := FReadBuffer.Size;
928 end;
929
930 SetLength( Result, len);
931
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200932 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200933 FReadBuffer.Position := 0;
934 FReadBuffer.Read( Pointer(@Result[0])^, len );
935 end;
936end;
937
Jens Geyer17c3ad92017-09-05 20:31:27 +0200938procedure TBufferedStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +0100939var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200940begin
941 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200942 if count > 0 then begin
943 if IsOpen then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100944 pTmp := pBuf;
945 Inc( pTmp, offset);
946 FWriteBuffer.Write( pTmp^, count );
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200947 if FWriteBuffer.Size > FBufSize then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200948 Flush;
949 end;
950 end;
951 end;
952end;
953
954{ TStreamTransportImpl }
955
Jens Geyerd5436f52014-10-03 19:50:38 +0200956constructor TStreamTransportImpl.Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);
957begin
958 inherited Create;
959 FInputStream := AInputStream;
960 FOutputStream := AOutputStream;
961end;
962
963destructor TStreamTransportImpl.Destroy;
964begin
965 FInputStream := nil;
966 FOutputStream := nil;
967 inherited;
968end;
969
Jens Geyer20e727e2018-06-22 22:39:57 +0200970procedure TStreamTransportImpl.Close;
971begin
972 FInputStream := nil;
973 FOutputStream := nil;
974end;
975
Jens Geyerd5436f52014-10-03 19:50:38 +0200976procedure TStreamTransportImpl.Flush;
977begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100978 if FOutputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200979 raise TTransportExceptionNotOpen.Create('Cannot flush null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +0200980 end;
981
982 FOutputStream.Flush;
983end;
984
985function TStreamTransportImpl.GetInputStream: IThriftStream;
986begin
987 Result := FInputStream;
988end;
989
990function TStreamTransportImpl.GetIsOpen: Boolean;
991begin
992 Result := True;
993end;
994
995function TStreamTransportImpl.GetOutputStream: IThriftStream;
996begin
Jens Geyer02fbe0e2018-03-19 17:35:44 +0100997 Result := FOutputStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200998end;
999
1000procedure TStreamTransportImpl.Open;
1001begin
Jens Geyer2646bd62019-11-09 23:24:52 +01001002 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +02001003end;
1004
Jens Geyer17c3ad92017-09-05 20:31:27 +02001005function TStreamTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001006begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001007 if FInputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001008 raise TTransportExceptionNotOpen.Create('Cannot read from null inputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001009 end;
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001010
Jens Geyer17c3ad92017-09-05 20:31:27 +02001011 Result := FInputStream.Read( pBuf,buflen, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001012end;
1013
Jens Geyer17c3ad92017-09-05 20:31:27 +02001014procedure TStreamTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001015begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001016 if FOutputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001017 raise TTransportExceptionNotOpen.Create('Cannot write to null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001018 end;
1019
Jens Geyer17c3ad92017-09-05 20:31:27 +02001020 FOutputStream.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001021end;
1022
1023{ TBufferedTransportImpl }
1024
1025constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport);
1026begin
1027 //no inherited;
1028 Create( ATransport, 1024 );
1029end;
1030
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001031constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport; ABufSize: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001032begin
1033 inherited Create;
1034 FTransport := ATransport;
1035 FBufSize := ABufSize;
1036 InitBuffers;
1037end;
1038
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001039procedure TBufferedTransportImpl.Close;
1040begin
1041 FTransport.Close;
1042 FInputBuffer := nil;
1043 FOutputBuffer := nil;
1044end;
1045
Jens Geyerd5436f52014-10-03 19:50:38 +02001046procedure TBufferedTransportImpl.Flush;
1047begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001048 if FOutputBuffer <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001049 FOutputBuffer.Flush;
1050 end;
1051end;
1052
1053function TBufferedTransportImpl.GetIsOpen: Boolean;
1054begin
1055 Result := FTransport.IsOpen;
1056end;
1057
1058function TBufferedTransportImpl.GetUnderlyingTransport: ITransport;
1059begin
1060 Result := FTransport;
1061end;
1062
1063procedure TBufferedTransportImpl.InitBuffers;
1064begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001065 if FTransport.InputStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001066 FInputBuffer := TBufferedStreamImpl.Create( FTransport.InputStream, FBufSize );
1067 end;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001068 if FTransport.OutputStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001069 FOutputBuffer := TBufferedStreamImpl.Create( FTransport.OutputStream, FBufSize );
1070 end;
1071end;
1072
1073procedure TBufferedTransportImpl.Open;
1074begin
Jens Geyera0cf38e2018-04-04 17:31:52 +02001075 FTransport.Open;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001076 InitBuffers; // we need to get the buffers to match FTransport substreams again
Jens Geyerd5436f52014-10-03 19:50:38 +02001077end;
1078
Jens Geyer17c3ad92017-09-05 20:31:27 +02001079function TBufferedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001080begin
1081 Result := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001082 if FInputBuffer <> nil then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001083 Result := FInputBuffer.Read( pBuf,buflen, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001084 end;
1085end;
1086
Jens Geyer17c3ad92017-09-05 20:31:27 +02001087procedure TBufferedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001088begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001089 if FOutputBuffer <> nil then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001090 FOutputBuffer.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001091 end;
1092end;
1093
1094{ TFramedTransportImpl }
1095
Jens Geyerd5436f52014-10-03 19:50:38 +02001096constructor TFramedTransportImpl.Create;
1097begin
1098 inherited Create;
Jens Geyerd5436f52014-10-03 19:50:38 +02001099
Jens Geyer2646bd62019-11-09 23:24:52 +01001100 InitMaxFrameSize;
1101 InitWriteBuffer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001102end;
1103
1104constructor TFramedTransportImpl.Create( const ATrans: ITransport);
1105begin
1106 inherited Create;
Jens Geyer2646bd62019-11-09 23:24:52 +01001107
1108 InitMaxFrameSize;
Jens Geyerd5436f52014-10-03 19:50:38 +02001109 InitWriteBuffer;
1110 FTransport := ATrans;
1111end;
1112
1113destructor TFramedTransportImpl.Destroy;
1114begin
1115 FWriteBuffer.Free;
1116 FReadBuffer.Free;
1117 inherited;
1118end;
1119
Jens Geyer2646bd62019-11-09 23:24:52 +01001120procedure TFramedTransportImpl.InitMaxFrameSize;
1121begin
1122 FMaxFrameSize := DEFAULT_MAX_LENGTH;
1123end;
1124
1125procedure TFramedTransportImpl.Close;
1126begin
1127 FTransport.Close;
1128end;
1129
Jens Geyerd5436f52014-10-03 19:50:38 +02001130procedure TFramedTransportImpl.Flush;
1131var
1132 buf : TBytes;
1133 len : Integer;
1134 data_len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001135begin
1136 len := FWriteBuffer.Size;
1137 SetLength( buf, len);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001138 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001139 System.Move( FWriteBuffer.Memory^, buf[0], len );
1140 end;
1141
Jens Geyer2646bd62019-11-09 23:24:52 +01001142 data_len := len - SizeOf(TFramedHeader);
Jens Geyer30ed90e2016-03-10 20:12:49 +01001143 if (data_len < 0) then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001144 raise TTransportExceptionUnknown.Create('TFramedTransport.Flush: data_len < 0' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001145 end;
1146
1147 InitWriteBuffer;
1148
1149 buf[0] := Byte($FF and (data_len shr 24));
1150 buf[1] := Byte($FF and (data_len shr 16));
1151 buf[2] := Byte($FF and (data_len shr 8));
1152 buf[3] := Byte($FF and data_len);
1153
1154 FTransport.Write( buf, 0, len );
1155 FTransport.Flush;
1156end;
1157
1158function TFramedTransportImpl.GetIsOpen: Boolean;
1159begin
1160 Result := FTransport.IsOpen;
1161end;
1162
1163type
1164 TAccessMemoryStream = class(TMemoryStream)
1165 end;
1166
1167procedure TFramedTransportImpl.InitWriteBuffer;
Jens Geyer2646bd62019-11-09 23:24:52 +01001168const DUMMY_HEADER : TFramedHeader = 0;
Jens Geyerd5436f52014-10-03 19:50:38 +02001169begin
1170 FWriteBuffer.Free;
1171 FWriteBuffer := TMemoryStream.Create;
1172 TAccessMemoryStream(FWriteBuffer).Capacity := 1024;
Jens Geyer2646bd62019-11-09 23:24:52 +01001173 FWriteBuffer.Write( DUMMY_HEADER, SizeOf(DUMMY_HEADER));
Jens Geyerd5436f52014-10-03 19:50:38 +02001174end;
1175
1176procedure TFramedTransportImpl.Open;
1177begin
1178 FTransport.Open;
1179end;
1180
Jens Geyer17c3ad92017-09-05 20:31:27 +02001181function TFramedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001182var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001183begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001184 if len > (buflen-off)
1185 then len := buflen-off;
1186
Jens Geyer5089b0a2018-02-01 22:37:18 +01001187 pTmp := pBuf;
1188 Inc( pTmp, off);
1189
Jens Geyer17c3ad92017-09-05 20:31:27 +02001190 if (FReadBuffer <> nil) and (len > 0) then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001191 result := FReadBuffer.Read( pTmp^, len);
Jens Geyer17c3ad92017-09-05 20:31:27 +02001192 if result > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001193 Exit;
1194 end;
1195 end;
1196
1197 ReadFrame;
1198 if len > 0
Jens Geyer5089b0a2018-02-01 22:37:18 +01001199 then Result := FReadBuffer.Read( pTmp^, len)
Jens Geyerd5436f52014-10-03 19:50:38 +02001200 else Result := 0;
1201end;
1202
1203procedure TFramedTransportImpl.ReadFrame;
1204var
Jens Geyer2646bd62019-11-09 23:24:52 +01001205 i32rd : packed array[0..SizeOf(TFramedHeader)-1] of Byte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001206 size : Integer;
1207 buff : TBytes;
1208begin
Jens Geyer2646bd62019-11-09 23:24:52 +01001209 FTransport.ReadAll( @i32rd[0], SizeOf(i32rd), 0, SizeOf(i32rd));
Jens Geyerd5436f52014-10-03 19:50:38 +02001210 size :=
1211 ((i32rd[0] and $FF) shl 24) or
1212 ((i32rd[1] and $FF) shl 16) or
1213 ((i32rd[2] and $FF) shl 8) or
1214 (i32rd[3] and $FF);
Jens Geyer2646bd62019-11-09 23:24:52 +01001215
1216 if size < 0 then begin
1217 Close();
1218 raise TTransportExceptionCorruptedData.Create('Read a negative frame size ('+IntToStr(size)+')');
1219 end;
1220
1221 if size > FMaxFrameSize then begin
1222 Close();
1223 raise TTransportExceptionCorruptedData.Create('Frame size ('+IntToStr(size)+') larger than allowed maximum ('+IntToStr(FMaxFrameSize)+')');
1224 end;
1225
Jens Geyerd5436f52014-10-03 19:50:38 +02001226 SetLength( buff, size );
1227 FTransport.ReadAll( buff, 0, size );
1228 FReadBuffer.Free;
1229 FReadBuffer := TMemoryStream.Create;
Jens Geyera76e6c72017-09-08 21:03:30 +02001230 if Length(buff) > 0
1231 then FReadBuffer.Write( Pointer(@buff[0])^, size );
Jens Geyerd5436f52014-10-03 19:50:38 +02001232 FReadBuffer.Position := 0;
1233end;
1234
Jens Geyer17c3ad92017-09-05 20:31:27 +02001235procedure TFramedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001236var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001237begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001238 if len > 0 then begin
1239 pTmp := pBuf;
1240 Inc( pTmp, off);
1241
1242 FWriteBuffer.Write( pTmp^, len );
1243 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001244end;
1245
1246{ TFramedTransport.TFactory }
1247
1248function TFramedTransportImpl.TFactory.GetTransport( const ATrans: ITransport): ITransport;
1249begin
1250 Result := TFramedTransportImpl.Create( ATrans );
1251end;
1252
1253{ TTcpSocketStreamImpl }
1254
1255procedure TTcpSocketStreamImpl.Close;
1256begin
1257 FTcpClient.Close;
1258end;
1259
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001260{$IFDEF OLD_SOCKETS}
1261constructor TTcpSocketStreamImpl.Create( const ATcpClient: TCustomIpClient; const aTimeout : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001262begin
1263 inherited Create;
1264 FTcpClient := ATcpClient;
1265 FTimeout := aTimeout;
1266end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001267{$ELSE}
1268constructor TTcpSocketStreamImpl.Create( const ATcpClient: TSocket; const aTimeout : Longword);
1269begin
1270 inherited Create;
1271 FTcpClient := ATcpClient;
1272 if aTimeout = 0 then
1273 FTcpClient.RecvTimeout := SLEEP_TIME
1274 else
1275 FTcpClient.RecvTimeout := aTimeout;
1276 FTcpClient.SendTimeout := aTimeout;
1277end;
1278{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001279
1280procedure TTcpSocketStreamImpl.Flush;
1281begin
1282
1283end;
1284
1285function TTcpSocketStreamImpl.IsOpen: Boolean;
1286begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001287{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001288 Result := FTcpClient.Active;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001289{$ELSE}
1290 Result := FTcpClient.IsOpen;
1291{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001292end;
1293
1294procedure TTcpSocketStreamImpl.Open;
1295begin
1296 FTcpClient.Open;
1297end;
1298
1299
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001300{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001301function TTcpSocketStreamImpl.Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
1302 TimeOut: Integer; var wsaError : Integer): Integer;
1303var
1304 ReadFds: TFDset;
1305 ReadFdsptr: PFDset;
1306 WriteFds: TFDset;
1307 WriteFdsptr: PFDset;
1308 ExceptFds: TFDset;
1309 ExceptFdsptr: PFDset;
1310 tv: timeval;
1311 Timeptr: PTimeval;
1312 socket : TSocket;
1313begin
1314 if not FTcpClient.Active then begin
1315 wsaError := WSAEINVAL;
1316 Exit( SOCKET_ERROR);
1317 end;
1318
1319 socket := FTcpClient.Handle;
1320
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001321 if Assigned(ReadReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001322 ReadFdsptr := @ReadFds;
1323 FD_ZERO(ReadFds);
1324 FD_SET(socket, ReadFds);
1325 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001326 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001327 ReadFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001328 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001329
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001330 if Assigned(WriteReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001331 WriteFdsptr := @WriteFds;
1332 FD_ZERO(WriteFds);
1333 FD_SET(socket, WriteFds);
1334 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001335 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001336 WriteFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001337 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001338
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001339 if Assigned(ExceptFlag) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001340 ExceptFdsptr := @ExceptFds;
1341 FD_ZERO(ExceptFds);
1342 FD_SET(socket, ExceptFds);
1343 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001344 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001345 ExceptFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001346 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001347
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001348 if TimeOut >= 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001349 tv.tv_sec := TimeOut div 1000;
1350 tv.tv_usec := 1000 * (TimeOut mod 1000);
1351 Timeptr := @tv;
1352 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001353 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001354 Timeptr := nil; // wait forever
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001355 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001356
1357 wsaError := 0;
1358 try
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001359 {$IFDEF MSWINDOWS}
1360 {$IFDEF OLD_UNIT_NAMES}
1361 result := WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1362 {$ELSE}
1363 result := Winapi.WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1364 {$ENDIF}
1365 {$ENDIF}
1366 {$IFDEF LINUX}
1367 result := Libc.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1368 {$ENDIF}
1369
Jens Geyerd5436f52014-10-03 19:50:38 +02001370 if result = SOCKET_ERROR
1371 then wsaError := WSAGetLastError;
1372
1373 except
1374 result := SOCKET_ERROR;
1375 end;
1376
1377 if Assigned(ReadReady) then
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001378 ReadReady^ := FD_ISSET(socket, ReadFds);
1379
Jens Geyerd5436f52014-10-03 19:50:38 +02001380 if Assigned(WriteReady) then
1381 WriteReady^ := FD_ISSET(socket, WriteFds);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001382
Jens Geyerd5436f52014-10-03 19:50:38 +02001383 if Assigned(ExceptFlag) then
1384 ExceptFlag^ := FD_ISSET(socket, ExceptFds);
1385end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001386{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001387
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001388{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001389function TTcpSocketStreamImpl.WaitForData( TimeOut : Integer; pBuf : Pointer;
1390 DesiredBytes : Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001391 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001392var bCanRead, bError : Boolean;
1393 retval : Integer;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001394const
1395 MSG_PEEK = {$IFDEF OLD_UNIT_NAMES} WinSock.MSG_PEEK {$ELSE} Winapi.WinSock.MSG_PEEK {$ENDIF};
Jens Geyerd5436f52014-10-03 19:50:38 +02001396begin
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001397 bytesReady := 0;
1398
Jens Geyerd5436f52014-10-03 19:50:38 +02001399 // The select function returns the total number of socket handles that are ready
1400 // and contained in the fd_set structures, zero if the time limit expired,
1401 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1402 // WSAGetLastError can be used to retrieve a specific error code.
1403 retval := Self.Select( @bCanRead, nil, @bError, TimeOut, wsaError);
1404 if retval = SOCKET_ERROR
1405 then Exit( TWaitForData.wfd_Error);
1406 if (retval = 0) or not bCanRead
1407 then Exit( TWaitForData.wfd_Timeout);
1408
1409 // recv() returns the number of bytes received, or -1 if an error occurred.
1410 // The return value will be 0 when the peer has performed an orderly shutdown.
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001411
1412 retval := recv( FTcpClient.Handle, pBuf^, DesiredBytes, MSG_PEEK);
Jens Geyerd5436f52014-10-03 19:50:38 +02001413 if retval <= 0
1414 then Exit( TWaitForData.wfd_Error);
1415
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001416 // at least we have some data
1417 bytesReady := Min( retval, DesiredBytes);
1418 result := TWaitForData.wfd_HaveData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001419end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001420{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001421
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001422{$IFDEF OLD_SOCKETS}
Jens Geyer17c3ad92017-09-05 20:31:27 +02001423function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001424// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001425var wfd : TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001426 wsaError,
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001427 msecs : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001428 nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001429 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001430begin
1431 inherited;
1432
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001433 if FTimeout > 0
1434 then msecs := FTimeout
1435 else msecs := DEFAULT_THRIFT_TIMEOUT;
1436
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001437 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001438 pTmp := pBuf;
1439 Inc( pTmp, offset);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001440 while count > 0 do begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001441
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001442 while TRUE do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001443 wfd := WaitForData( msecs, pTmp, count, wsaError, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001444 case wfd of
Jens Geyer65b17462016-03-09 00:07:46 +01001445 TWaitForData.wfd_Error : Exit;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001446 TWaitForData.wfd_HaveData : Break;
1447 TWaitForData.wfd_Timeout : begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001448 if (FTimeout = 0)
1449 then Exit
1450 else begin
Jens Geyere0e32402016-04-20 21:50:48 +02001451 raise TTransportExceptionTimedOut.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001452
1453 end;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001454 end;
1455 else
1456 ASSERT( FALSE);
Jens Geyerd5436f52014-10-03 19:50:38 +02001457 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001458 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001459
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001460 // reduce the timeout once we got data
1461 if FTimeout > 0
1462 then msecs := FTimeout div 10
1463 else msecs := DEFAULT_THRIFT_TIMEOUT div 10;
1464 msecs := Max( msecs, 200);
1465
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001466 ASSERT( nBytes <= count);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001467 nBytes := FTcpClient.ReceiveBuf( pTmp^, nBytes);
1468 Inc( pTmp, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001469 Dec( count, nBytes);
1470 Inc( result, nBytes);
1471 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001472end;
1473
1474function TTcpSocketStreamImpl.ToArray: TBytes;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001475// old sockets version
1476var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001477begin
1478 len := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001479 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001480 len := FTcpClient.BytesReceived;
1481 end;
1482
1483 SetLength( Result, len );
1484
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001485 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001486 FTcpClient.ReceiveBuf( Pointer(@Result[0])^, len);
1487 end;
1488end;
1489
Jens Geyer17c3ad92017-09-05 20:31:27 +02001490procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001491// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001492var bCanWrite, bError : Boolean;
1493 retval, wsaError : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001494 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001495begin
1496 inherited;
1497
1498 if not FTcpClient.Active
Jens Geyere0e32402016-04-20 21:50:48 +02001499 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerd5436f52014-10-03 19:50:38 +02001500
1501 // The select function returns the total number of socket handles that are ready
1502 // and contained in the fd_set structures, zero if the time limit expired,
1503 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1504 // WSAGetLastError can be used to retrieve a specific error code.
1505 retval := Self.Select( nil, @bCanWrite, @bError, FTimeOut, wsaError);
1506 if retval = SOCKET_ERROR
Jens Geyere0e32402016-04-20 21:50:48 +02001507 then raise TTransportExceptionUnknown.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001508
Jens Geyerd5436f52014-10-03 19:50:38 +02001509 if (retval = 0)
Jens Geyere0e32402016-04-20 21:50:48 +02001510 then raise TTransportExceptionTimedOut.Create('timed out');
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001511
Jens Geyerd5436f52014-10-03 19:50:38 +02001512 if bError or not bCanWrite
Jens Geyere0e32402016-04-20 21:50:48 +02001513 then raise TTransportExceptionUnknown.Create('unknown error');
Jens Geyerd5436f52014-10-03 19:50:38 +02001514
Jens Geyer5089b0a2018-02-01 22:37:18 +01001515 pTmp := pBuf;
1516 Inc( pTmp, offset);
1517 FTcpClient.SendBuf( pTmp^, count);
Jens Geyerd5436f52014-10-03 19:50:38 +02001518end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001519
1520{$ELSE}
1521
Jens Geyer17c3ad92017-09-05 20:31:27 +02001522function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001523// new sockets version
1524var nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001525 pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001526begin
1527 inherited;
1528
1529 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001530 pTmp := pBuf;
1531 Inc( pTmp, offset);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001532 while count > 0 do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001533 nBytes := FTcpClient.Read( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001534 if nBytes = 0 then Exit;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001535 Inc( pTmp, nBytes);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001536 Dec( count, nBytes);
1537 Inc( result, nBytes);
1538 end;
1539end;
1540
1541function TTcpSocketStreamImpl.ToArray: TBytes;
1542// new sockets version
1543var len : Integer;
1544begin
1545 len := 0;
1546 try
1547 if FTcpClient.Peek then
1548 repeat
1549 SetLength(Result, Length(Result) + 1024);
1550 len := FTcpClient.Read(Result[Length(Result) - 1024], 1024);
1551 until len < 1024;
1552 except
1553 on TTransportException do begin { don't allow default exceptions } end;
1554 else raise;
1555 end;
1556 if len > 0 then
1557 SetLength(Result, Length(Result) - 1024 + len);
1558end;
1559
Jens Geyer17c3ad92017-09-05 20:31:27 +02001560procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001561// new sockets version
Jens Geyer5089b0a2018-02-01 22:37:18 +01001562var pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001563begin
1564 inherited;
1565
1566 if not FTcpClient.IsOpen
Kyle Johnsone363a342016-04-22 19:11:16 -05001567 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001568
Jens Geyer5089b0a2018-02-01 22:37:18 +01001569 pTmp := pBuf;
1570 Inc( pTmp, offset);
1571 FTcpClient.Write( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001572end;
1573
Jens Geyer23d67462015-12-19 11:44:57 +01001574{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001575
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001576
Jens Geyerd5436f52014-10-03 19:50:38 +02001577{$IF CompilerVersion < 21.0}
1578initialization
1579begin
1580 TFramedTransportImpl_Initialize;
1581end;
1582{$IFEND}
1583
1584
1585end.