blob: dad9ab7f3057fbbecaaa55c94d4fcd691160614e [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}
32 ActiveX, msxml, WinSock, Sockets,
Nick4f5229e2016-04-14 16:43:22 +030033 {$ELSE}
Jens Geyer9f7f11e2016-04-14 21:37:11 +020034 Winapi.ActiveX, Winapi.msxml, Winapi.WinSock,
35 {$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,
Nick4f5229e2016-04-14 16:43:22 +030044 Thrift.Stream;
Jens Geyerd5436f52014-10-03 19:50:38 +020045
46type
47 ITransport = interface
Jens Geyer17c3ad92017-09-05 20:31:27 +020048 ['{DB84961E-8BB3-4532-99E1-A8C7AC2300F7}']
Jens Geyerd5436f52014-10-03 19:50:38 +020049 function GetIsOpen: Boolean;
50 property IsOpen: Boolean read GetIsOpen;
51 function Peek: Boolean;
52 procedure Open;
53 procedure Close;
Jens Geyer17c3ad92017-09-05 20:31:27 +020054 function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
55 function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
56 function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload;
57 function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020058 procedure Write( const buf: TBytes); overload;
59 procedure Write( const buf: TBytes; off: Integer; len: Integer); overload;
Jens Geyer17c3ad92017-09-05 20:31:27 +020060 procedure Write( const pBuf : Pointer; off, len : Integer); overload;
61 procedure Write( const pBuf : Pointer; len : Integer); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020062 procedure Flush;
63 end;
64
65 TTransportImpl = class( TInterfacedObject, ITransport)
66 protected
67 function GetIsOpen: Boolean; virtual; abstract;
68 property IsOpen: Boolean read GetIsOpen;
69 function Peek: Boolean; virtual;
70 procedure Open(); virtual; abstract;
71 procedure Close(); virtual; abstract;
Jens Geyer17c3ad92017-09-05 20:31:27 +020072 function Read(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
73 function Read(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual; abstract;
74 function ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer; overload; inline;
75 function ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; overload; virtual;
76 procedure Write( const buf: TBytes); overload; inline;
77 procedure Write( const buf: TBytes; off: Integer; len: Integer); overload; inline;
78 procedure Write( const pBuf : Pointer; len : Integer); overload; inline;
79 procedure Write( const pBuf : Pointer; off, len : Integer); overload; virtual; abstract;
Jens Geyerd5436f52014-10-03 19:50:38 +020080 procedure Flush; virtual;
81 end;
82
Jens Geyer606f1ef2018-04-09 23:09:41 +020083 TTransportException = class( TException)
Jens Geyerd5436f52014-10-03 19:50:38 +020084 public
85 type
86 TExceptionType = (
87 Unknown,
88 NotOpen,
89 AlreadyOpen,
90 TimedOut,
Jens Geyerbea9bbe2016-04-20 00:02:40 +020091 EndOfFile,
92 BadArgs,
93 Interrupted
Jens Geyerd5436f52014-10-03 19:50:38 +020094 );
95 private
Jens Geyere0e32402016-04-20 21:50:48 +020096 function GetType: TExceptionType;
97 protected
98 constructor HiddenCreate(const Msg: string);
Jens Geyerd5436f52014-10-03 19:50:38 +020099 public
Jens Geyere0e32402016-04-20 21:50:48 +0200100 class function Create( AType: TExceptionType): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
101 class function Create( const msg: string): TTransportException; reintroduce; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
102 class function Create( AType: TExceptionType; const msg: string): TTransportException; overload; deprecated 'Use specialized TTransportException types (or regenerate from IDL)';
103 property Type_: TExceptionType read GetType;
Jens Geyerd5436f52014-10-03 19:50:38 +0200104 end;
105
Jens Geyere0e32402016-04-20 21:50:48 +0200106 // Needed to remove deprecation warning
107 TTransportExceptionSpecialized = class abstract (TTransportException)
108 public
109 constructor Create(const Msg: string);
110 end;
111
112 TTransportExceptionUnknown = class (TTransportExceptionSpecialized);
113 TTransportExceptionNotOpen = class (TTransportExceptionSpecialized);
114 TTransportExceptionAlreadyOpen = class (TTransportExceptionSpecialized);
115 TTransportExceptionTimedOut = class (TTransportExceptionSpecialized);
116 TTransportExceptionEndOfFile = class (TTransportExceptionSpecialized);
117 TTransportExceptionBadArgs = class (TTransportExceptionSpecialized);
118 TTransportExceptionInterrupted = class (TTransportExceptionSpecialized);
119
Jens Geyerd5436f52014-10-03 19:50:38 +0200120 IHTTPClient = interface( ITransport )
Jens Geyer20e727e2018-06-22 22:39:57 +0200121 ['{BA142D12-8AE6-4B50-9E33-6B7843B21D73}']
122 procedure SetDnsResolveTimeout(const Value: Integer);
123 function GetDnsResolveTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200124 procedure SetConnectionTimeout(const Value: Integer);
125 function GetConnectionTimeout: Integer;
Jens Geyer20e727e2018-06-22 22:39:57 +0200126 procedure SetSendTimeout(const Value: Integer);
127 function GetSendTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200128 procedure SetReadTimeout(const Value: Integer);
129 function GetReadTimeout: Integer;
130 function GetCustomHeaders: IThriftDictionary<string,string>;
131 procedure SendRequest;
Jens Geyer20e727e2018-06-22 22:39:57 +0200132
133 property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200134 property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
Jens Geyer20e727e2018-06-22 22:39:57 +0200135 property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200136 property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
137 property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
138 end;
139
140 THTTPClientImpl = class( TTransportImpl, IHTTPClient)
141 private
142 FUri : string;
143 FInputStream : IThriftStream;
144 FOutputStream : IThriftStream;
Jens Geyer20e727e2018-06-22 22:39:57 +0200145 FDnsResolveTimeout : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200146 FConnectionTimeout : Integer;
Jens Geyer20e727e2018-06-22 22:39:57 +0200147 FSendTimeout : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200148 FReadTimeout : Integer;
149 FCustomHeaders : IThriftDictionary<string,string>;
150
151 function CreateRequest: IXMLHTTPRequest;
152 protected
153 function GetIsOpen: Boolean; override;
154 procedure Open(); override;
155 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200156 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
157 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200158 procedure Flush; override;
159
Jens Geyer20e727e2018-06-22 22:39:57 +0200160 procedure SetDnsResolveTimeout(const Value: Integer);
161 function GetDnsResolveTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200162 procedure SetConnectionTimeout(const Value: Integer);
163 function GetConnectionTimeout: Integer;
Jens Geyer20e727e2018-06-22 22:39:57 +0200164 procedure SetSendTimeout(const Value: Integer);
165 function GetSendTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200166 procedure SetReadTimeout(const Value: Integer);
167 function GetReadTimeout: Integer;
Jens Geyer20e727e2018-06-22 22:39:57 +0200168
Jens Geyerd5436f52014-10-03 19:50:38 +0200169 function GetCustomHeaders: IThriftDictionary<string,string>;
170 procedure SendRequest;
Jens Geyer20e727e2018-06-22 22:39:57 +0200171 property DnsResolveTimeout: Integer read GetDnsResolveTimeout write SetDnsResolveTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200172 property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout;
Jens Geyer20e727e2018-06-22 22:39:57 +0200173 property SendTimeout: Integer read GetSendTimeout write SetSendTimeout;
Jens Geyerd5436f52014-10-03 19:50:38 +0200174 property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
175 property CustomHeaders: IThriftDictionary<string,string> read GetCustomHeaders;
176 public
177 constructor Create( const AUri: string);
178 destructor Destroy; override;
179 end;
180
181 IServerTransport = interface
182 ['{C43B87ED-69EA-47C4-B77C-15E288252900}']
183 procedure Listen;
184 procedure Close;
185 function Accept( const fnAccepting: TProc): ITransport;
186 end;
187
188 TServerTransportImpl = class( TInterfacedObject, IServerTransport)
189 protected
190 procedure Listen; virtual; abstract;
191 procedure Close; virtual; abstract;
192 function Accept( const fnAccepting: TProc): ITransport; virtual; abstract;
193 end;
194
195 ITransportFactory = interface
196 ['{DD809446-000F-49E1-9BFF-E0D0DC76A9D7}']
197 function GetTransport( const ATrans: ITransport): ITransport;
198 end;
199
200 TTransportFactoryImpl = class( TInterfacedObject, ITransportFactory)
201 function GetTransport( const ATrans: ITransport): ITransport; virtual;
202 end;
203
204 TTcpSocketStreamImpl = class( TThriftStreamImpl )
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200205{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200206 private type
207 TWaitForData = ( wfd_HaveData, wfd_Timeout, wfd_Error);
208 private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200209 FTcpClient : TCustomIpClient;
Jens Geyerd5436f52014-10-03 19:50:38 +0200210 FTimeout : Integer;
211 function Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
212 TimeOut: Integer; var wsaError : Integer): Integer;
213 function WaitForData( TimeOut : Integer; pBuf : Pointer; DesiredBytes: Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +0200214 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200215{$ELSE}
216 FTcpClient: TSocket;
217 protected const
218 SLEEP_TIME = 200;
219{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200220 protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200221 procedure Write( const pBuf : Pointer; offset, count: Integer); override;
222 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200223 procedure Open; override;
224 procedure Close; override;
225 procedure Flush; override;
226
227 function IsOpen: Boolean; override;
228 function ToArray: TBytes; override;
229 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200230{$IFDEF OLD_SOCKETS}
231 constructor Create( const ATcpClient: TCustomIpClient; const aTimeout : Integer = 0);
232{$ELSE}
233 constructor Create( const ATcpClient: TSocket; const aTimeout : Longword = 0);
234{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200235 end;
236
237 IStreamTransport = interface( ITransport )
238 ['{A8479B47-2A3E-4421-A9A0-D5A9EDCC634A}']
239 function GetInputStream: IThriftStream;
240 function GetOutputStream: IThriftStream;
241 property InputStream : IThriftStream read GetInputStream;
242 property OutputStream : IThriftStream read GetOutputStream;
243 end;
244
245 TStreamTransportImpl = class( TTransportImpl, IStreamTransport)
246 protected
247 FInputStream : IThriftStream;
248 FOutputStream : IThriftStream;
249 protected
250 function GetIsOpen: Boolean; override;
251
252 function GetInputStream: IThriftStream;
253 function GetOutputStream: IThriftStream;
254 public
255 property InputStream : IThriftStream read GetInputStream;
256 property OutputStream : IThriftStream read GetOutputStream;
257
258 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 Geyerd5436f52014-10-03 19:50:38 +0200263 constructor Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);
264 destructor Destroy; override;
265 end;
266
267 TBufferedStreamImpl = class( TThriftStreamImpl)
268 private
269 FStream : IThriftStream;
270 FBufSize : Integer;
271 FReadBuffer : TMemoryStream;
272 FWriteBuffer : TMemoryStream;
273 protected
Jens Geyer17c3ad92017-09-05 20:31:27 +0200274 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
275 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200276 procedure Open; override;
277 procedure Close; override;
278 procedure Flush; override;
279 function IsOpen: Boolean; override;
280 function ToArray: TBytes; override;
281 public
282 constructor Create( const AStream: IThriftStream; ABufSize: Integer);
283 destructor Destroy; override;
284 end;
285
286 TServerSocketImpl = class( TServerTransportImpl)
287 private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200288{$IFDEF OLD_SOCKETS}
289 FServer : TTcpServer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200290 FPort : Integer;
291 FClientTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200292{$ELSE}
293 FServer: TServerSocket;
294{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200295 FUseBufferedSocket : Boolean;
296 FOwnsServer : Boolean;
297 protected
298 function Accept( const fnAccepting: TProc) : ITransport; override;
299 public
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200300{$IFDEF OLD_SOCKETS}
301 constructor Create( const AServer: TTcpServer; AClientTimeout: Integer = 0); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +0200302 constructor Create( APort: Integer; AClientTimeout: Integer = 0; AUseBufferedSockets: Boolean = FALSE); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200303{$ELSE}
304 constructor Create( const AServer: TServerSocket; AClientTimeout: Longword = 0); overload;
305 constructor Create( APort: Integer; AClientTimeout: Longword = 0; AUseBufferedSockets: Boolean = FALSE); overload;
306{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200307 destructor Destroy; override;
308 procedure Listen; override;
309 procedure Close; override;
310 end;
311
312 TBufferedTransportImpl = class( TTransportImpl )
313 private
314 FInputBuffer : IThriftStream;
315 FOutputBuffer : IThriftStream;
316 FTransport : IStreamTransport;
317 FBufSize : Integer;
318
319 procedure InitBuffers;
320 function GetUnderlyingTransport: ITransport;
321 protected
322 function GetIsOpen: Boolean; override;
323 procedure Flush; override;
324 public
325 procedure Open(); override;
326 procedure Close(); override;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200327 function Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer; override;
328 procedure Write( const pBuf : Pointer; off, len : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200329 constructor Create( const ATransport : IStreamTransport ); overload;
330 constructor Create( const ATransport : IStreamTransport; ABufSize: Integer); overload;
331 property UnderlyingTransport: ITransport read GetUnderlyingTransport;
332 property IsOpen: Boolean read GetIsOpen;
333 end;
334
335 TSocketImpl = class(TStreamTransportImpl)
336 private
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200337{$IFDEF OLD_SOCKETS}
338 FClient : TCustomIpClient;
339{$ELSE}
340 FClient: TSocket;
341{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200342 FOwnsClient : Boolean;
343 FHost : string;
344 FPort : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200345{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200346 FTimeout : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200347{$ELSE}
348 FTimeout : Longword;
349{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200350
351 procedure InitSocket;
352 protected
353 function GetIsOpen: Boolean; override;
354 public
355 procedure Open; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200356{$IFDEF OLD_SOCKETS}
357 constructor Create( const AClient : TCustomIpClient; aOwnsClient : Boolean; ATimeout: Integer = 0); overload;
Jens Geyerd5436f52014-10-03 19:50:38 +0200358 constructor Create( const AHost: string; APort: Integer; ATimeout: Integer = 0); overload;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200359{$ELSE}
360 constructor Create(const AClient: TSocket; aOwnsClient: Boolean); overload;
361 constructor Create( const AHost: string; APort: Integer; ATimeout: Longword = 0); overload;
362{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200363 destructor Destroy; override;
364 procedure Close; override;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200365{$IFDEF OLD_SOCKETS}
366 property TcpClient: TCustomIpClient read FClient;
367{$ELSE}
368 property TcpClient: TSocket read FClient;
369{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200370 property Host : string read FHost;
371 property Port: Integer read FPort;
372 end;
373
374 TFramedTransportImpl = class( TTransportImpl)
375 private const
376 FHeaderSize : Integer = 4;
377 private class var
378 FHeader_Dummy : array of Byte;
379 protected
380 FTransport : ITransport;
381 FWriteBuffer : TMemoryStream;
382 FReadBuffer : TMemoryStream;
383
384 procedure InitWriteBuffer;
385 procedure ReadFrame;
386 public
387 type
388 TFactory = class( TTransportFactoryImpl )
389 public
390 function GetTransport( const ATrans: ITransport): ITransport; override;
391 end;
392
Jens Geyere0e32402016-04-20 21:50:48 +0200393 {$IFDEF HAVE_CLASS_CTOR}
Jens Geyerd5436f52014-10-03 19:50:38 +0200394 class constructor Create;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200395 {$ENDIF}
Jens Geyere0e32402016-04-20 21:50:48 +0200396
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 Geyer9f7f11e2016-04-14 21:37:11 +0200410{$IFNDEF HAVE_CLASS_CTOR}
Jens Geyerd5436f52014-10-03 19:50:38 +0200411procedure TFramedTransportImpl_Initialize;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200412{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200413
414const
415 DEFAULT_THRIFT_TIMEOUT = 5 * 1000; // ms
416
417
418implementation
419
420{ TTransportImpl }
421
422procedure TTransportImpl.Flush;
423begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200424 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200425end;
426
427function TTransportImpl.Peek: Boolean;
428begin
429 Result := IsOpen;
430end;
431
Jens Geyer17c3ad92017-09-05 20:31:27 +0200432function TTransportImpl.Read(var buf: TBytes; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200433begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200434 if Length(buf) > 0
435 then result := Read( @buf[0], Length(buf), off, len)
436 else result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200437end;
438
439function TTransportImpl.ReadAll(var buf: TBytes; off: Integer; len: Integer): Integer;
440begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200441 if Length(buf) > 0
442 then result := ReadAll( @buf[0], Length(buf), off, len)
443 else result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200444end;
445
446procedure TTransportImpl.Write( const buf: TBytes);
447begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200448 if Length(buf) > 0
449 then Write( @buf[0], 0, Length(buf));
Jens Geyer17c3ad92017-09-05 20:31:27 +0200450end;
451
452procedure TTransportImpl.Write( const buf: TBytes; off: Integer; len: Integer);
453begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200454 if Length(buf) > 0
455 then Write( @buf[0], off, len);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200456end;
457
458function TTransportImpl.ReadAll(const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
459var ret : Integer;
460begin
461 result := 0;
462 while result < len do begin
463 ret := Read( pBuf, buflen, off + result, len - result);
464 if ret > 0
465 then Inc( result, ret)
466 else raise TTransportExceptionNotOpen.Create( 'Cannot read, Remote side has closed' );
467 end;
468end;
469
470procedure TTransportImpl.Write( const pBuf : Pointer; len : Integer);
471begin
472 Self.Write( pBuf, 0, len);
Jens Geyerd5436f52014-10-03 19:50:38 +0200473end;
474
475{ THTTPClientImpl }
476
Jens Geyerd5436f52014-10-03 19:50:38 +0200477constructor THTTPClientImpl.Create(const AUri: string);
478begin
479 inherited Create;
480 FUri := AUri;
Jens Geyer20e727e2018-06-22 22:39:57 +0200481
482 // defaults according to MSDN
483 FDnsResolveTimeout := 0; // no timeout
484 FConnectionTimeout := 60 * 1000;
485 FSendTimeout := 30 * 1000;
486 FReadTimeout := 30 * 1000;
487
Jens Geyerd5436f52014-10-03 19:50:38 +0200488 FCustomHeaders := TThriftDictionaryImpl<string,string>.Create;
489 FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
490end;
491
492function THTTPClientImpl.CreateRequest: IXMLHTTPRequest;
493var
494 pair : TPair<string,string>;
Jens Geyer20e727e2018-06-22 22:39:57 +0200495 srvHttp : IServerXMLHTTPRequest;
Jens Geyerd5436f52014-10-03 19:50:38 +0200496begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200497 {$IF CompilerVersion >= 21.0}
Jens Geyer20e727e2018-06-22 22:39:57 +0200498 Result := CoServerXMLHTTP.Create;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200499 {$ELSE}
Jens Geyerd5436f52014-10-03 19:50:38 +0200500 Result := CoXMLHTTPRequest.Create;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200501 {$IFEND}
Jens Geyerd5436f52014-10-03 19:50:38 +0200502
Jens Geyer20e727e2018-06-22 22:39:57 +0200503 // setting a timeout value to 0 (zero) means "no timeout" for that setting
504 if Supports( result, IServerXMLHTTPRequest, srvHttp)
505 then srvHttp.setTimeouts( DnsResolveTimeout, ConnectionTimeout, SendTimeout, ReadTimeout);
506
Jens Geyerd5436f52014-10-03 19:50:38 +0200507 Result.open('POST', FUri, False, '', '');
508 Result.setRequestHeader( 'Content-Type', 'application/x-thrift');
509 Result.setRequestHeader( 'Accept', 'application/x-thrift');
510 Result.setRequestHeader( 'User-Agent', 'Delphi/IHTTPClient');
511
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200512 for pair in FCustomHeaders do begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200513 Result.setRequestHeader( pair.Key, pair.Value );
514 end;
515end;
516
517destructor THTTPClientImpl.Destroy;
518begin
519 Close;
520 inherited;
521end;
522
Jens Geyer20e727e2018-06-22 22:39:57 +0200523function THTTPClientImpl.GetDnsResolveTimeout: Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200524begin
Jens Geyer20e727e2018-06-22 22:39:57 +0200525 Result := FDnsResolveTimeout;
526end;
527
528procedure THTTPClientImpl.SetDnsResolveTimeout(const Value: Integer);
529begin
530 FDnsResolveTimeout := Value;
Jens Geyerd5436f52014-10-03 19:50:38 +0200531end;
532
533function THTTPClientImpl.GetConnectionTimeout: Integer;
534begin
535 Result := FConnectionTimeout;
536end;
537
Jens Geyer20e727e2018-06-22 22:39:57 +0200538procedure THTTPClientImpl.SetConnectionTimeout(const Value: Integer);
539begin
540 FConnectionTimeout := Value;
541end;
542
543function THTTPClientImpl.GetSendTimeout: Integer;
544begin
545 Result := FSendTimeout;
546end;
547
548procedure THTTPClientImpl.SetSendTimeout(const Value: Integer);
549begin
550 FSendTimeout := Value;
551end;
552
553function THTTPClientImpl.GetReadTimeout: Integer;
554begin
555 Result := FReadTimeout;
556end;
557
558procedure THTTPClientImpl.SetReadTimeout(const Value: Integer);
559begin
560 FReadTimeout := Value;
561end;
562
Jens Geyerd5436f52014-10-03 19:50:38 +0200563function THTTPClientImpl.GetCustomHeaders: IThriftDictionary<string,string>;
564begin
565 Result := FCustomHeaders;
566end;
567
568function THTTPClientImpl.GetIsOpen: Boolean;
569begin
570 Result := True;
571end;
572
Jens Geyerd5436f52014-10-03 19:50:38 +0200573procedure THTTPClientImpl.Open;
574begin
Jens Geyer20e727e2018-06-22 22:39:57 +0200575 FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
576end;
577
578procedure THTTPClientImpl.Close;
579begin
580 FInputStream := nil;
581 FOutputStream := nil;
582end;
583
584procedure THTTPClientImpl.Flush;
585begin
586 try
587 SendRequest;
588 finally
589 FOutputStream := nil;
590 FOutputStream := TThriftStreamAdapterDelphi.Create( TMemoryStream.Create, True);
591 ASSERT( FOutputStream <> nil);
592 end;
Jens Geyerd5436f52014-10-03 19:50:38 +0200593end;
594
Jens Geyer17c3ad92017-09-05 20:31:27 +0200595function THTTPClientImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200596begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100597 if FInputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200598 raise TTransportExceptionNotOpen.Create('No request has been sent');
Jens Geyerd5436f52014-10-03 19:50:38 +0200599 end;
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100600
Jens Geyerd5436f52014-10-03 19:50:38 +0200601 try
Jens Geyer17c3ad92017-09-05 20:31:27 +0200602 Result := FInputStream.Read( pBuf, buflen, off, len)
Jens Geyerd5436f52014-10-03 19:50:38 +0200603 except
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100604 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200605 do raise TTransportExceptionUnknown.Create(E.Message);
Jens Geyerd5436f52014-10-03 19:50:38 +0200606 end;
607end;
608
609procedure THTTPClientImpl.SendRequest;
610var
611 xmlhttp : IXMLHTTPRequest;
612 ms : TMemoryStream;
613 a : TBytes;
614 len : Integer;
615begin
616 xmlhttp := CreateRequest;
617
618 ms := TMemoryStream.Create;
619 try
620 a := FOutputStream.ToArray;
621 len := Length(a);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200622 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200623 ms.WriteBuffer( Pointer(@a[0])^, len);
624 end;
625 ms.Position := 0;
626 xmlhttp.send( IUnknown( TStreamAdapter.Create( ms, soReference )));
627 FInputStream := nil;
628 FInputStream := TThriftStreamAdapterCOM.Create( IUnknown( xmlhttp.responseStream) as IStream);
629 finally
630 ms.Free;
631 end;
632end;
633
Jens Geyer17c3ad92017-09-05 20:31:27 +0200634procedure THTTPClientImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200635begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200636 FOutputStream.Write( pBuf, off, len);
Jens Geyerd5436f52014-10-03 19:50:38 +0200637end;
638
639{ TTransportException }
640
Jens Geyere0e32402016-04-20 21:50:48 +0200641function TTransportException.GetType: TExceptionType;
642begin
643 if Self is TTransportExceptionNotOpen then Result := TExceptionType.NotOpen
644 else if Self is TTransportExceptionAlreadyOpen then Result := TExceptionType.AlreadyOpen
645 else if Self is TTransportExceptionTimedOut then Result := TExceptionType.TimedOut
646 else if Self is TTransportExceptionEndOfFile then Result := TExceptionType.EndOfFile
647 else if Self is TTransportExceptionBadArgs then Result := TExceptionType.BadArgs
648 else if Self is TTransportExceptionInterrupted then Result := TExceptionType.Interrupted
649 else Result := TExceptionType.Unknown;
650end;
651
652constructor TTransportException.HiddenCreate(const Msg: string);
653begin
654 inherited Create(Msg);
655end;
656
657class function TTransportException.Create(AType: TExceptionType): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200658begin
659 //no inherited;
Jens Geyere0e32402016-04-20 21:50:48 +0200660{$WARN SYMBOL_DEPRECATED OFF}
661 Result := Create(AType, '')
662{$WARN SYMBOL_DEPRECATED DEFAULT}
Jens Geyerd5436f52014-10-03 19:50:38 +0200663end;
664
Jens Geyere0e32402016-04-20 21:50:48 +0200665class function TTransportException.Create(AType: TExceptionType;
666 const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200667begin
Jens Geyere0e32402016-04-20 21:50:48 +0200668 case AType of
669 TExceptionType.NotOpen: Result := TTransportExceptionNotOpen.Create(msg);
670 TExceptionType.AlreadyOpen: Result := TTransportExceptionAlreadyOpen.Create(msg);
671 TExceptionType.TimedOut: Result := TTransportExceptionTimedOut.Create(msg);
672 TExceptionType.EndOfFile: Result := TTransportExceptionEndOfFile.Create(msg);
673 TExceptionType.BadArgs: Result := TTransportExceptionBadArgs.Create(msg);
674 TExceptionType.Interrupted: Result := TTransportExceptionInterrupted.Create(msg);
675 else
676 Result := TTransportExceptionUnknown.Create(msg);
677 end;
Jens Geyerd5436f52014-10-03 19:50:38 +0200678end;
679
Jens Geyere0e32402016-04-20 21:50:48 +0200680class function TTransportException.Create(const msg: string): TTransportException;
Jens Geyerd5436f52014-10-03 19:50:38 +0200681begin
Jens Geyere0e32402016-04-20 21:50:48 +0200682 Result := TTransportExceptionUnknown.Create(Msg);
683end;
684
685{ TTransportExceptionSpecialized }
686
687constructor TTransportExceptionSpecialized.Create(const Msg: string);
688begin
689 inherited HiddenCreate(Msg);
Jens Geyerd5436f52014-10-03 19:50:38 +0200690end;
691
692{ TTransportFactoryImpl }
693
694function TTransportFactoryImpl.GetTransport( const ATrans: ITransport): ITransport;
695begin
696 Result := ATrans;
697end;
698
699{ TServerSocket }
700
Jens Geyer23d67462015-12-19 11:44:57 +0100701{$IFDEF OLD_SOCKETS}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200702constructor TServerSocketImpl.Create( const AServer: TTcpServer; AClientTimeout: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200703begin
704 inherited Create;
705 FServer := AServer;
706 FClientTimeout := AClientTimeout;
707end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200708{$ELSE}
709constructor TServerSocketImpl.Create( const AServer: TServerSocket; AClientTimeout: Longword);
Jens Geyerd5436f52014-10-03 19:50:38 +0200710begin
711 inherited Create;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200712 FServer := AServer;
713 FServer.RecvTimeout := AClientTimeout;
714 FServer.SendTimeout := AClientTimeout;
715end;
716{$ENDIF}
717
718{$IFDEF OLD_SOCKETS}
719constructor TServerSocketImpl.Create(APort, AClientTimeout: Integer; AUseBufferedSockets: Boolean);
720{$ELSE}
721constructor TServerSocketImpl.Create(APort: Integer; AClientTimeout: Longword; AUseBufferedSockets: Boolean);
722{$ENDIF}
723begin
724 inherited Create;
725{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200726 FPort := APort;
727 FClientTimeout := AClientTimeout;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200728 FServer := TTcpServer.Create( nil );
Jens Geyerd5436f52014-10-03 19:50:38 +0200729 FServer.BlockMode := bmBlocking;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200730 {$IF CompilerVersion >= 21.0}
Jens Geyerd5436f52014-10-03 19:50:38 +0200731 FServer.LocalPort := AnsiString( IntToStr( FPort));
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200732 {$ELSE}
Jens Geyerd5436f52014-10-03 19:50:38 +0200733 FServer.LocalPort := IntToStr( FPort);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200734 {$IFEND}
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200735{$ELSE}
736 FServer := TServerSocket.Create(APort, AClientTimeout, AClientTimeout);
737{$ENDIF}
738 FUseBufferedSocket := AUseBufferedSockets;
739 FOwnsServer := True;
Jens Geyerd5436f52014-10-03 19:50:38 +0200740end;
741
742destructor TServerSocketImpl.Destroy;
743begin
744 if FOwnsServer then begin
745 FServer.Free;
746 FServer := nil;
747 end;
748 inherited;
749end;
750
751function TServerSocketImpl.Accept( const fnAccepting: TProc): ITransport;
752var
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200753{$IFDEF OLD_SOCKETS}
754 client : TCustomIpClient;
755{$ELSE}
756 client: TSocket;
757{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200758 trans : IStreamTransport;
759begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100760 if FServer = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200761 raise TTransportExceptionNotOpen.Create('No underlying server socket.');
Jens Geyerd5436f52014-10-03 19:50:38 +0200762 end;
763
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200764{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200765 client := nil;
766 try
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200767 client := TCustomIpClient.Create(nil);
Jens Geyerd5436f52014-10-03 19:50:38 +0200768
769 if Assigned(fnAccepting)
770 then fnAccepting();
771
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100772 if not FServer.Accept( client) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200773 client.Free;
774 Result := nil;
775 Exit;
776 end;
777
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100778 if client = nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200779 Result := nil;
780 Exit;
781 end;
782
783 trans := TSocketImpl.Create( client, TRUE, FClientTimeout);
784 client := nil; // trans owns it now
785
786 if FUseBufferedSocket
787 then result := TBufferedTransportImpl.Create( trans)
788 else result := trans;
789
790 except
791 on E: Exception do begin
792 client.Free;
Jens Geyere0e32402016-04-20 21:50:48 +0200793 raise TTransportExceptionUnknown.Create(E.ToString);
Jens Geyerd5436f52014-10-03 19:50:38 +0200794 end;
795 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200796{$ELSE}
797 if Assigned(fnAccepting) then
798 fnAccepting();
799
800 client := FServer.Accept;
801 try
802 trans := TSocketImpl.Create(client, True);
803 client := nil;
804
805 if FUseBufferedSocket then
806 Result := TBufferedTransportImpl.Create(trans)
807 else
808 Result := trans;
809 except
810 client.Free;
811 raise;
812 end;
813{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200814end;
815
816procedure TServerSocketImpl.Listen;
817begin
818 if FServer <> nil then
819 begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200820{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200821 try
822 FServer.Active := True;
823 except
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200824 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200825 do raise TTransportExceptionUnknown.Create('Could not accept on listening socket: ' + E.Message);
Jens Geyerd5436f52014-10-03 19:50:38 +0200826 end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200827{$ELSE}
828 FServer.Listen;
829{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200830 end;
831end;
832
833procedure TServerSocketImpl.Close;
834begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200835 if FServer <> nil then
836{$IFDEF OLD_SOCKETS}
837 try
838 FServer.Active := False;
839 except
840 on E: Exception
Jens Geyere0e32402016-04-20 21:50:48 +0200841 do raise TTransportExceptionUnknown.Create('Error on closing socket : ' + E.Message);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200842 end;
843{$ELSE}
844 FServer.Close;
845{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200846end;
847
848{ TSocket }
849
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200850{$IFDEF OLD_SOCKETS}
851constructor TSocketImpl.Create( const AClient : TCustomIpClient; aOwnsClient : Boolean; ATimeout: Integer = 0);
Jens Geyerd5436f52014-10-03 19:50:38 +0200852var stream : IThriftStream;
853begin
854 FClient := AClient;
855 FTimeout := ATimeout;
856 FOwnsClient := aOwnsClient;
857 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
858 inherited Create( stream, stream);
859end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200860{$ELSE}
861constructor TSocketImpl.Create(const AClient: TSocket; aOwnsClient: Boolean);
862var stream : IThriftStream;
863begin
864 FClient := AClient;
865 FTimeout := AClient.RecvTimeout;
866 FOwnsClient := aOwnsClient;
867 stream := TTcpSocketStreamImpl.Create(FClient, FTimeout);
868 inherited Create(stream, stream);
869end;
870{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200871
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200872{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200873constructor TSocketImpl.Create(const AHost: string; APort, ATimeout: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200874{$ELSE}
875constructor TSocketImpl.Create(const AHost: string; APort: Integer; ATimeout: Longword);
876{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200877begin
878 inherited Create(nil,nil);
879 FHost := AHost;
880 FPort := APort;
881 FTimeout := ATimeout;
882 InitSocket;
883end;
884
885destructor TSocketImpl.Destroy;
886begin
887 if FOwnsClient
888 then FreeAndNil( FClient);
889 inherited;
890end;
891
892procedure TSocketImpl.Close;
893begin
894 inherited Close;
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200895
896 FInputStream := nil;
897 FOutputStream := nil;
898
Jens Geyerd5436f52014-10-03 19:50:38 +0200899 if FOwnsClient
Jens Geyer3c0edfa2018-04-02 13:57:55 +0200900 then FreeAndNil( FClient)
901 else FClient := nil;
Jens Geyerd5436f52014-10-03 19:50:38 +0200902end;
903
904function TSocketImpl.GetIsOpen: Boolean;
905begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200906{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200907 Result := (FClient <> nil) and FClient.Connected;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200908{$ELSE}
909 Result := (FClient <> nil) and FClient.IsOpen
910{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200911end;
912
913procedure TSocketImpl.InitSocket;
914var
915 stream : IThriftStream;
916begin
917 if FOwnsClient
918 then FreeAndNil( FClient)
919 else FClient := nil;
920
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200921{$IFDEF OLD_SOCKETS}
922 FClient := TTcpClient.Create( nil);
923{$ELSE}
924 FClient := TSocket.Create(FHost, FPort);
925{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200926 FOwnsClient := True;
927
928 stream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
929 FInputStream := stream;
930 FOutputStream := stream;
931end;
932
933procedure TSocketImpl.Open;
934begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100935 if IsOpen then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200936 raise TTransportExceptionAlreadyOpen.Create('Socket already connected');
Jens Geyerd5436f52014-10-03 19:50:38 +0200937 end;
938
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100939 if FHost = '' then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200940 raise TTransportExceptionNotOpen.Create('Cannot open null host');
Jens Geyerd5436f52014-10-03 19:50:38 +0200941 end;
942
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100943 if Port <= 0 then begin
Jens Geyere0e32402016-04-20 21:50:48 +0200944 raise TTransportExceptionNotOpen.Create('Cannot open without port');
Jens Geyerd5436f52014-10-03 19:50:38 +0200945 end;
946
Jens Geyer6f6aa8a2016-03-10 19:47:12 +0100947 if FClient = nil
948 then InitSocket;
Jens Geyerd5436f52014-10-03 19:50:38 +0200949
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200950{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +0200951 FClient.RemoteHost := TSocketHost( Host);
952 FClient.RemotePort := TSocketPort( IntToStr( Port));
953 FClient.Connect;
Jens Geyerbea9bbe2016-04-20 00:02:40 +0200954{$ELSE}
955 FClient.Open;
956{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +0200957
958 FInputStream := TTcpSocketStreamImpl.Create( FClient, FTimeout);
959 FOutputStream := FInputStream;
960end;
961
962{ TBufferedStream }
963
964procedure TBufferedStreamImpl.Close;
965begin
966 Flush;
967 FStream := nil;
968
969 FReadBuffer.Free;
970 FReadBuffer := nil;
971
972 FWriteBuffer.Free;
973 FWriteBuffer := nil;
974end;
975
976constructor TBufferedStreamImpl.Create( const AStream: IThriftStream; ABufSize: Integer);
977begin
978 inherited Create;
979 FStream := AStream;
980 FBufSize := ABufSize;
981 FReadBuffer := TMemoryStream.Create;
982 FWriteBuffer := TMemoryStream.Create;
983end;
984
985destructor TBufferedStreamImpl.Destroy;
986begin
987 Close;
988 inherited;
989end;
990
991procedure TBufferedStreamImpl.Flush;
992var
993 buf : TBytes;
994 len : Integer;
995begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200996 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200997 len := FWriteBuffer.Size;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200998 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200999 SetLength( buf, len );
1000 FWriteBuffer.Position := 0;
1001 FWriteBuffer.Read( Pointer(@buf[0])^, len );
1002 FStream.Write( buf, 0, len );
1003 end;
1004 FWriteBuffer.Clear;
1005 end;
1006end;
1007
1008function TBufferedStreamImpl.IsOpen: Boolean;
1009begin
1010 Result := (FWriteBuffer <> nil)
1011 and (FReadBuffer <> nil)
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001012 and (FStream <> nil)
1013 and FStream.IsOpen;
Jens Geyerd5436f52014-10-03 19:50:38 +02001014end;
1015
1016procedure TBufferedStreamImpl.Open;
1017begin
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001018 FStream.Open;
Jens Geyerd5436f52014-10-03 19:50:38 +02001019end;
1020
Jens Geyer17c3ad92017-09-05 20:31:27 +02001021function TBufferedStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001022var
1023 nRead : Integer;
1024 tempbuf : TBytes;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001025 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001026begin
1027 inherited;
1028 Result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001029
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001030 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001031 while count > 0 do begin
1032
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001033 if FReadBuffer.Position >= FReadBuffer.Size then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001034 FReadBuffer.Clear;
1035 SetLength( tempbuf, FBufSize);
1036 nRead := FStream.Read( tempbuf, 0, FBufSize );
1037 if nRead = 0 then Break; // avoid infinite loop
1038
1039 FReadBuffer.WriteBuffer( Pointer(@tempbuf[0])^, nRead );
1040 FReadBuffer.Position := 0;
1041 end;
1042
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001043 if FReadBuffer.Position < FReadBuffer.Size then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001044 nRead := Min( FReadBuffer.Size - FReadBuffer.Position, count);
1045 pTmp := pBuf;
1046 Inc( pTmp, offset);
1047 Inc( Result, FReadBuffer.Read( pTmp^, nRead));
Jens Geyerd5436f52014-10-03 19:50:38 +02001048 Dec( count, nRead);
1049 Inc( offset, nRead);
1050 end;
1051 end;
1052 end;
1053end;
1054
1055function TBufferedStreamImpl.ToArray: TBytes;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001056var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001057begin
1058 len := 0;
1059
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001060 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001061 len := FReadBuffer.Size;
1062 end;
1063
1064 SetLength( Result, len);
1065
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001066 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001067 FReadBuffer.Position := 0;
1068 FReadBuffer.Read( Pointer(@Result[0])^, len );
1069 end;
1070end;
1071
Jens Geyer17c3ad92017-09-05 20:31:27 +02001072procedure TBufferedStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001073var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001074begin
1075 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001076 if count > 0 then begin
1077 if IsOpen then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001078 pTmp := pBuf;
1079 Inc( pTmp, offset);
1080 FWriteBuffer.Write( pTmp^, count );
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001081 if FWriteBuffer.Size > FBufSize then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001082 Flush;
1083 end;
1084 end;
1085 end;
1086end;
1087
1088{ TStreamTransportImpl }
1089
Jens Geyerd5436f52014-10-03 19:50:38 +02001090constructor TStreamTransportImpl.Create( const AInputStream : IThriftStream; const AOutputStream : IThriftStream);
1091begin
1092 inherited Create;
1093 FInputStream := AInputStream;
1094 FOutputStream := AOutputStream;
1095end;
1096
1097destructor TStreamTransportImpl.Destroy;
1098begin
1099 FInputStream := nil;
1100 FOutputStream := nil;
1101 inherited;
1102end;
1103
Jens Geyer20e727e2018-06-22 22:39:57 +02001104procedure TStreamTransportImpl.Close;
1105begin
1106 FInputStream := nil;
1107 FOutputStream := nil;
1108end;
1109
Jens Geyerd5436f52014-10-03 19:50:38 +02001110procedure TStreamTransportImpl.Flush;
1111begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001112 if FOutputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001113 raise TTransportExceptionNotOpen.Create('Cannot flush null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001114 end;
1115
1116 FOutputStream.Flush;
1117end;
1118
1119function TStreamTransportImpl.GetInputStream: IThriftStream;
1120begin
1121 Result := FInputStream;
1122end;
1123
1124function TStreamTransportImpl.GetIsOpen: Boolean;
1125begin
1126 Result := True;
1127end;
1128
1129function TStreamTransportImpl.GetOutputStream: IThriftStream;
1130begin
Jens Geyer02fbe0e2018-03-19 17:35:44 +01001131 Result := FOutputStream;
Jens Geyerd5436f52014-10-03 19:50:38 +02001132end;
1133
1134procedure TStreamTransportImpl.Open;
1135begin
1136
1137end;
1138
Jens Geyer17c3ad92017-09-05 20:31:27 +02001139function TStreamTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001140begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001141 if FInputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001142 raise TTransportExceptionNotOpen.Create('Cannot read from null inputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001143 end;
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001144
Jens Geyer17c3ad92017-09-05 20:31:27 +02001145 Result := FInputStream.Read( pBuf,buflen, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001146end;
1147
Jens Geyer17c3ad92017-09-05 20:31:27 +02001148procedure TStreamTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001149begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001150 if FOutputStream = nil then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001151 raise TTransportExceptionNotOpen.Create('Cannot write to null outputstream' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001152 end;
1153
Jens Geyer17c3ad92017-09-05 20:31:27 +02001154 FOutputStream.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001155end;
1156
1157{ TBufferedTransportImpl }
1158
1159constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport);
1160begin
1161 //no inherited;
1162 Create( ATransport, 1024 );
1163end;
1164
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001165constructor TBufferedTransportImpl.Create( const ATransport: IStreamTransport; ABufSize: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001166begin
1167 inherited Create;
1168 FTransport := ATransport;
1169 FBufSize := ABufSize;
1170 InitBuffers;
1171end;
1172
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001173procedure TBufferedTransportImpl.Close;
1174begin
1175 FTransport.Close;
1176 FInputBuffer := nil;
1177 FOutputBuffer := nil;
1178end;
1179
Jens Geyerd5436f52014-10-03 19:50:38 +02001180procedure TBufferedTransportImpl.Flush;
1181begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001182 if FOutputBuffer <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001183 FOutputBuffer.Flush;
1184 end;
1185end;
1186
1187function TBufferedTransportImpl.GetIsOpen: Boolean;
1188begin
1189 Result := FTransport.IsOpen;
1190end;
1191
1192function TBufferedTransportImpl.GetUnderlyingTransport: ITransport;
1193begin
1194 Result := FTransport;
1195end;
1196
1197procedure TBufferedTransportImpl.InitBuffers;
1198begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001199 if FTransport.InputStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001200 FInputBuffer := TBufferedStreamImpl.Create( FTransport.InputStream, FBufSize );
1201 end;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001202 if FTransport.OutputStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001203 FOutputBuffer := TBufferedStreamImpl.Create( FTransport.OutputStream, FBufSize );
1204 end;
1205end;
1206
1207procedure TBufferedTransportImpl.Open;
1208begin
Jens Geyera0cf38e2018-04-04 17:31:52 +02001209 FTransport.Open;
Jens Geyer3c0edfa2018-04-02 13:57:55 +02001210 InitBuffers; // we need to get the buffers to match FTransport substreams again
Jens Geyerd5436f52014-10-03 19:50:38 +02001211end;
1212
Jens Geyer17c3ad92017-09-05 20:31:27 +02001213function TBufferedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001214begin
1215 Result := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001216 if FInputBuffer <> nil then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001217 Result := FInputBuffer.Read( pBuf,buflen, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001218 end;
1219end;
1220
Jens Geyer17c3ad92017-09-05 20:31:27 +02001221procedure TBufferedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001222begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001223 if FOutputBuffer <> nil then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001224 FOutputBuffer.Write( pBuf, off, len );
Jens Geyerd5436f52014-10-03 19:50:38 +02001225 end;
1226end;
1227
1228{ TFramedTransportImpl }
1229
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001230{$IFDEF HAVE_CLASS_CTOR}
1231class constructor TFramedTransportImpl.Create;
1232begin
1233 SetLength( FHeader_Dummy, FHeaderSize);
1234 FillChar( FHeader_Dummy[0], Length( FHeader_Dummy) * SizeOf( Byte ), 0);
1235end;
1236{$ELSE}
Jens Geyerd5436f52014-10-03 19:50:38 +02001237procedure TFramedTransportImpl_Initialize;
1238begin
1239 SetLength( TFramedTransportImpl.FHeader_Dummy, TFramedTransportImpl.FHeaderSize);
1240 FillChar( TFramedTransportImpl.FHeader_Dummy[0],
1241 Length( TFramedTransportImpl.FHeader_Dummy) * SizeOf( Byte ), 0);
1242end;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001243{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001244
1245constructor TFramedTransportImpl.Create;
1246begin
1247 inherited Create;
1248 InitWriteBuffer;
1249end;
1250
1251procedure TFramedTransportImpl.Close;
1252begin
1253 FTransport.Close;
1254end;
1255
1256constructor TFramedTransportImpl.Create( const ATrans: ITransport);
1257begin
1258 inherited Create;
1259 InitWriteBuffer;
1260 FTransport := ATrans;
1261end;
1262
1263destructor TFramedTransportImpl.Destroy;
1264begin
1265 FWriteBuffer.Free;
1266 FReadBuffer.Free;
1267 inherited;
1268end;
1269
1270procedure TFramedTransportImpl.Flush;
1271var
1272 buf : TBytes;
1273 len : Integer;
1274 data_len : Integer;
1275
1276begin
1277 len := FWriteBuffer.Size;
1278 SetLength( buf, len);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001279 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001280 System.Move( FWriteBuffer.Memory^, buf[0], len );
1281 end;
1282
1283 data_len := len - FHeaderSize;
Jens Geyer30ed90e2016-03-10 20:12:49 +01001284 if (data_len < 0) then begin
Jens Geyere0e32402016-04-20 21:50:48 +02001285 raise TTransportExceptionUnknown.Create('TFramedTransport.Flush: data_len < 0' );
Jens Geyerd5436f52014-10-03 19:50:38 +02001286 end;
1287
1288 InitWriteBuffer;
1289
1290 buf[0] := Byte($FF and (data_len shr 24));
1291 buf[1] := Byte($FF and (data_len shr 16));
1292 buf[2] := Byte($FF and (data_len shr 8));
1293 buf[3] := Byte($FF and data_len);
1294
1295 FTransport.Write( buf, 0, len );
1296 FTransport.Flush;
1297end;
1298
1299function TFramedTransportImpl.GetIsOpen: Boolean;
1300begin
1301 Result := FTransport.IsOpen;
1302end;
1303
1304type
1305 TAccessMemoryStream = class(TMemoryStream)
1306 end;
1307
1308procedure TFramedTransportImpl.InitWriteBuffer;
1309begin
1310 FWriteBuffer.Free;
1311 FWriteBuffer := TMemoryStream.Create;
1312 TAccessMemoryStream(FWriteBuffer).Capacity := 1024;
1313 FWriteBuffer.Write( Pointer(@FHeader_Dummy[0])^, FHeaderSize);
1314end;
1315
1316procedure TFramedTransportImpl.Open;
1317begin
1318 FTransport.Open;
1319end;
1320
Jens Geyer17c3ad92017-09-05 20:31:27 +02001321function TFramedTransportImpl.Read( const pBuf : Pointer; const buflen : Integer; off: Integer; len: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001322var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001323begin
Jens Geyer17c3ad92017-09-05 20:31:27 +02001324 if len > (buflen-off)
1325 then len := buflen-off;
1326
Jens Geyer5089b0a2018-02-01 22:37:18 +01001327 pTmp := pBuf;
1328 Inc( pTmp, off);
1329
Jens Geyer17c3ad92017-09-05 20:31:27 +02001330 if (FReadBuffer <> nil) and (len > 0) then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001331 result := FReadBuffer.Read( pTmp^, len);
Jens Geyer17c3ad92017-09-05 20:31:27 +02001332 if result > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001333 Exit;
1334 end;
1335 end;
1336
1337 ReadFrame;
1338 if len > 0
Jens Geyer5089b0a2018-02-01 22:37:18 +01001339 then Result := FReadBuffer.Read( pTmp^, len)
Jens Geyerd5436f52014-10-03 19:50:38 +02001340 else Result := 0;
1341end;
1342
1343procedure TFramedTransportImpl.ReadFrame;
1344var
1345 i32rd : TBytes;
1346 size : Integer;
1347 buff : TBytes;
1348begin
1349 SetLength( i32rd, FHeaderSize );
1350 FTransport.ReadAll( i32rd, 0, FHeaderSize);
1351 size :=
1352 ((i32rd[0] and $FF) shl 24) or
1353 ((i32rd[1] and $FF) shl 16) or
1354 ((i32rd[2] and $FF) shl 8) or
1355 (i32rd[3] and $FF);
1356 SetLength( buff, size );
1357 FTransport.ReadAll( buff, 0, size );
1358 FReadBuffer.Free;
1359 FReadBuffer := TMemoryStream.Create;
Jens Geyera76e6c72017-09-08 21:03:30 +02001360 if Length(buff) > 0
1361 then FReadBuffer.Write( Pointer(@buff[0])^, size );
Jens Geyerd5436f52014-10-03 19:50:38 +02001362 FReadBuffer.Position := 0;
1363end;
1364
Jens Geyer17c3ad92017-09-05 20:31:27 +02001365procedure TFramedTransportImpl.Write( const pBuf : Pointer; off, len : Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001366var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001367begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001368 if len > 0 then begin
1369 pTmp := pBuf;
1370 Inc( pTmp, off);
1371
1372 FWriteBuffer.Write( pTmp^, len );
1373 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001374end;
1375
1376{ TFramedTransport.TFactory }
1377
1378function TFramedTransportImpl.TFactory.GetTransport( const ATrans: ITransport): ITransport;
1379begin
1380 Result := TFramedTransportImpl.Create( ATrans );
1381end;
1382
1383{ TTcpSocketStreamImpl }
1384
1385procedure TTcpSocketStreamImpl.Close;
1386begin
1387 FTcpClient.Close;
1388end;
1389
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001390{$IFDEF OLD_SOCKETS}
1391constructor TTcpSocketStreamImpl.Create( const ATcpClient: TCustomIpClient; const aTimeout : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +02001392begin
1393 inherited Create;
1394 FTcpClient := ATcpClient;
1395 FTimeout := aTimeout;
1396end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001397{$ELSE}
1398constructor TTcpSocketStreamImpl.Create( const ATcpClient: TSocket; const aTimeout : Longword);
1399begin
1400 inherited Create;
1401 FTcpClient := ATcpClient;
1402 if aTimeout = 0 then
1403 FTcpClient.RecvTimeout := SLEEP_TIME
1404 else
1405 FTcpClient.RecvTimeout := aTimeout;
1406 FTcpClient.SendTimeout := aTimeout;
1407end;
1408{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001409
1410procedure TTcpSocketStreamImpl.Flush;
1411begin
1412
1413end;
1414
1415function TTcpSocketStreamImpl.IsOpen: Boolean;
1416begin
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001417{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001418 Result := FTcpClient.Active;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001419{$ELSE}
1420 Result := FTcpClient.IsOpen;
1421{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001422end;
1423
1424procedure TTcpSocketStreamImpl.Open;
1425begin
1426 FTcpClient.Open;
1427end;
1428
1429
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001430{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001431function TTcpSocketStreamImpl.Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
1432 TimeOut: Integer; var wsaError : Integer): Integer;
1433var
1434 ReadFds: TFDset;
1435 ReadFdsptr: PFDset;
1436 WriteFds: TFDset;
1437 WriteFdsptr: PFDset;
1438 ExceptFds: TFDset;
1439 ExceptFdsptr: PFDset;
1440 tv: timeval;
1441 Timeptr: PTimeval;
1442 socket : TSocket;
1443begin
1444 if not FTcpClient.Active then begin
1445 wsaError := WSAEINVAL;
1446 Exit( SOCKET_ERROR);
1447 end;
1448
1449 socket := FTcpClient.Handle;
1450
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001451 if Assigned(ReadReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001452 ReadFdsptr := @ReadFds;
1453 FD_ZERO(ReadFds);
1454 FD_SET(socket, ReadFds);
1455 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001456 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001457 ReadFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001458 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001459
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001460 if Assigned(WriteReady) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001461 WriteFdsptr := @WriteFds;
1462 FD_ZERO(WriteFds);
1463 FD_SET(socket, WriteFds);
1464 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001465 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001466 WriteFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001467 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001468
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001469 if Assigned(ExceptFlag) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001470 ExceptFdsptr := @ExceptFds;
1471 FD_ZERO(ExceptFds);
1472 FD_SET(socket, ExceptFds);
1473 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001474 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001475 ExceptFdsptr := nil;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001476 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001477
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001478 if TimeOut >= 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001479 tv.tv_sec := TimeOut div 1000;
1480 tv.tv_usec := 1000 * (TimeOut mod 1000);
1481 Timeptr := @tv;
1482 end
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001483 else begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001484 Timeptr := nil; // wait forever
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001485 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001486
1487 wsaError := 0;
1488 try
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001489 {$IFDEF MSWINDOWS}
1490 {$IFDEF OLD_UNIT_NAMES}
1491 result := WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1492 {$ELSE}
1493 result := Winapi.WinSock.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1494 {$ENDIF}
1495 {$ENDIF}
1496 {$IFDEF LINUX}
1497 result := Libc.select( socket + 1, ReadFdsptr, WriteFdsptr, ExceptFdsptr, Timeptr);
1498 {$ENDIF}
1499
Jens Geyerd5436f52014-10-03 19:50:38 +02001500 if result = SOCKET_ERROR
1501 then wsaError := WSAGetLastError;
1502
1503 except
1504 result := SOCKET_ERROR;
1505 end;
1506
1507 if Assigned(ReadReady) then
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001508 ReadReady^ := FD_ISSET(socket, ReadFds);
1509
Jens Geyerd5436f52014-10-03 19:50:38 +02001510 if Assigned(WriteReady) then
1511 WriteReady^ := FD_ISSET(socket, WriteFds);
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001512
Jens Geyerd5436f52014-10-03 19:50:38 +02001513 if Assigned(ExceptFlag) then
1514 ExceptFlag^ := FD_ISSET(socket, ExceptFds);
1515end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001516{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001517
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001518{$IFDEF OLD_SOCKETS}
Jens Geyerd5436f52014-10-03 19:50:38 +02001519function TTcpSocketStreamImpl.WaitForData( TimeOut : Integer; pBuf : Pointer;
1520 DesiredBytes : Integer;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001521 var wsaError, bytesReady : Integer): TWaitForData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001522var bCanRead, bError : Boolean;
1523 retval : Integer;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001524const
1525 MSG_PEEK = {$IFDEF OLD_UNIT_NAMES} WinSock.MSG_PEEK {$ELSE} Winapi.WinSock.MSG_PEEK {$ENDIF};
Jens Geyerd5436f52014-10-03 19:50:38 +02001526begin
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001527 bytesReady := 0;
1528
Jens Geyerd5436f52014-10-03 19:50:38 +02001529 // The select function returns the total number of socket handles that are ready
1530 // and contained in the fd_set structures, zero if the time limit expired,
1531 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1532 // WSAGetLastError can be used to retrieve a specific error code.
1533 retval := Self.Select( @bCanRead, nil, @bError, TimeOut, wsaError);
1534 if retval = SOCKET_ERROR
1535 then Exit( TWaitForData.wfd_Error);
1536 if (retval = 0) or not bCanRead
1537 then Exit( TWaitForData.wfd_Timeout);
1538
1539 // recv() returns the number of bytes received, or -1 if an error occurred.
1540 // The return value will be 0 when the peer has performed an orderly shutdown.
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001541
1542 retval := recv( FTcpClient.Handle, pBuf^, DesiredBytes, MSG_PEEK);
Jens Geyerd5436f52014-10-03 19:50:38 +02001543 if retval <= 0
1544 then Exit( TWaitForData.wfd_Error);
1545
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001546 // at least we have some data
1547 bytesReady := Min( retval, DesiredBytes);
1548 result := TWaitForData.wfd_HaveData;
Jens Geyerd5436f52014-10-03 19:50:38 +02001549end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001550{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001551
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001552{$IFDEF OLD_SOCKETS}
Jens Geyer17c3ad92017-09-05 20:31:27 +02001553function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001554// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001555var wfd : TWaitForData;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001556 wsaError,
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001557 msecs : Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001558 nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001559 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001560begin
1561 inherited;
1562
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001563 if FTimeout > 0
1564 then msecs := FTimeout
1565 else msecs := DEFAULT_THRIFT_TIMEOUT;
1566
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001567 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001568 pTmp := pBuf;
1569 Inc( pTmp, offset);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001570 while count > 0 do begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001571
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001572 while TRUE do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001573 wfd := WaitForData( msecs, pTmp, count, wsaError, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001574 case wfd of
Jens Geyer65b17462016-03-09 00:07:46 +01001575 TWaitForData.wfd_Error : Exit;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001576 TWaitForData.wfd_HaveData : Break;
1577 TWaitForData.wfd_Timeout : begin
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001578 if (FTimeout = 0)
1579 then Exit
1580 else begin
Jens Geyere0e32402016-04-20 21:50:48 +02001581 raise TTransportExceptionTimedOut.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001582
1583 end;
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001584 end;
1585 else
1586 ASSERT( FALSE);
Jens Geyerd5436f52014-10-03 19:50:38 +02001587 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001588 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001589
Jens Geyer6f6aa8a2016-03-10 19:47:12 +01001590 // reduce the timeout once we got data
1591 if FTimeout > 0
1592 then msecs := FTimeout div 10
1593 else msecs := DEFAULT_THRIFT_TIMEOUT div 10;
1594 msecs := Max( msecs, 200);
1595
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001596 ASSERT( nBytes <= count);
Jens Geyer5089b0a2018-02-01 22:37:18 +01001597 nBytes := FTcpClient.ReceiveBuf( pTmp^, nBytes);
1598 Inc( pTmp, nBytes);
Jens Geyerbcb17bc2015-07-17 23:11:14 +02001599 Dec( count, nBytes);
1600 Inc( result, nBytes);
1601 end;
Jens Geyerd5436f52014-10-03 19:50:38 +02001602end;
1603
1604function TTcpSocketStreamImpl.ToArray: TBytes;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001605// old sockets version
1606var len : Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +02001607begin
1608 len := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001609 if IsOpen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001610 len := FTcpClient.BytesReceived;
1611 end;
1612
1613 SetLength( Result, len );
1614
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001615 if len > 0 then begin
Jens Geyerd5436f52014-10-03 19:50:38 +02001616 FTcpClient.ReceiveBuf( Pointer(@Result[0])^, len);
1617 end;
1618end;
1619
Jens Geyer17c3ad92017-09-05 20:31:27 +02001620procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001621// old sockets version
Jens Geyerd5436f52014-10-03 19:50:38 +02001622var bCanWrite, bError : Boolean;
1623 retval, wsaError : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001624 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +02001625begin
1626 inherited;
1627
1628 if not FTcpClient.Active
Jens Geyere0e32402016-04-20 21:50:48 +02001629 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerd5436f52014-10-03 19:50:38 +02001630
1631 // The select function returns the total number of socket handles that are ready
1632 // and contained in the fd_set structures, zero if the time limit expired,
1633 // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
1634 // WSAGetLastError can be used to retrieve a specific error code.
1635 retval := Self.Select( nil, @bCanWrite, @bError, FTimeOut, wsaError);
1636 if retval = SOCKET_ERROR
Jens Geyere0e32402016-04-20 21:50:48 +02001637 then raise TTransportExceptionUnknown.Create(SysErrorMessage(Cardinal(wsaError)));
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001638
Jens Geyerd5436f52014-10-03 19:50:38 +02001639 if (retval = 0)
Jens Geyere0e32402016-04-20 21:50:48 +02001640 then raise TTransportExceptionTimedOut.Create('timed out');
Jens Geyer9f7f11e2016-04-14 21:37:11 +02001641
Jens Geyerd5436f52014-10-03 19:50:38 +02001642 if bError or not bCanWrite
Jens Geyere0e32402016-04-20 21:50:48 +02001643 then raise TTransportExceptionUnknown.Create('unknown error');
Jens Geyerd5436f52014-10-03 19:50:38 +02001644
Jens Geyer5089b0a2018-02-01 22:37:18 +01001645 pTmp := pBuf;
1646 Inc( pTmp, offset);
1647 FTcpClient.SendBuf( pTmp^, count);
Jens Geyerd5436f52014-10-03 19:50:38 +02001648end;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001649
1650{$ELSE}
1651
Jens Geyer17c3ad92017-09-05 20:31:27 +02001652function TTcpSocketStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001653// new sockets version
1654var nBytes : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001655 pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001656begin
1657 inherited;
1658
1659 result := 0;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001660 pTmp := pBuf;
1661 Inc( pTmp, offset);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001662 while count > 0 do begin
Jens Geyer5089b0a2018-02-01 22:37:18 +01001663 nBytes := FTcpClient.Read( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001664 if nBytes = 0 then Exit;
Jens Geyer5089b0a2018-02-01 22:37:18 +01001665 Inc( pTmp, nBytes);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001666 Dec( count, nBytes);
1667 Inc( result, nBytes);
1668 end;
1669end;
1670
1671function TTcpSocketStreamImpl.ToArray: TBytes;
1672// new sockets version
1673var len : Integer;
1674begin
1675 len := 0;
1676 try
1677 if FTcpClient.Peek then
1678 repeat
1679 SetLength(Result, Length(Result) + 1024);
1680 len := FTcpClient.Read(Result[Length(Result) - 1024], 1024);
1681 until len < 1024;
1682 except
1683 on TTransportException do begin { don't allow default exceptions } end;
1684 else raise;
1685 end;
1686 if len > 0 then
1687 SetLength(Result, Length(Result) - 1024 + len);
1688end;
1689
Jens Geyer17c3ad92017-09-05 20:31:27 +02001690procedure TTcpSocketStreamImpl.Write( const pBuf : Pointer; offset, count: Integer);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001691// new sockets version
Jens Geyer5089b0a2018-02-01 22:37:18 +01001692var pTmp : PByte;
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001693begin
1694 inherited;
1695
1696 if not FTcpClient.IsOpen
Kyle Johnsone363a342016-04-22 19:11:16 -05001697 then raise TTransportExceptionNotOpen.Create('not open');
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001698
Jens Geyer5089b0a2018-02-01 22:37:18 +01001699 pTmp := pBuf;
1700 Inc( pTmp, offset);
1701 FTcpClient.Write( pTmp^, count);
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001702end;
1703
Jens Geyer23d67462015-12-19 11:44:57 +01001704{$ENDIF}
Jens Geyerd5436f52014-10-03 19:50:38 +02001705
Jens Geyerbea9bbe2016-04-20 00:02:40 +02001706
Jens Geyerd5436f52014-10-03 19:50:38 +02001707{$IF CompilerVersion < 21.0}
1708initialization
1709begin
1710 TFramedTransportImpl_Initialize;
1711end;
1712{$IFEND}
1713
1714
1715end.