IdTCPClient.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.38 1/15/05 2:14:58 PM RLebeau
  18. Removed virtual specifier from SetConnectTimeout() and SetReadTimeout(), not
  19. being used by any descendants.
  20. Rev 1.37 11/29/2004 11:49:24 PM JPMugaas
  21. Fixes for compiler errors.
  22. Rev 1.36 11/29/04 10:38:58 AM RLebeau
  23. Updated Connect() to release the IOHandler on error if implicitally created.
  24. Rev 1.35 11/28/04 2:28:22 PM RLebeau
  25. Added 'const' to various property setter parameters.
  26. Removed redundant getter methods.
  27. Rev 1.34 11/27/2004 8:27:44 PM JPMugaas
  28. Fix for compiler errors.
  29. Rev 1.33 11/26/04 3:46:10 PM RLebeau
  30. Added support for BoundIP and BoundPort properties
  31. Rev 1.32 2004.11.05 10:58:34 PM czhower
  32. Changed connect overloads for C#.
  33. Rev 1.31 8/8/04 12:32:08 AM RLebeau
  34. Redeclared ReadTimeout and ConnectTimeout properties as public instead of
  35. protected in TIdTCPClientCustom
  36. Rev 1.30 8/4/2004 5:37:34 AM DSiders
  37. Changed camel-casing on ReadTimeout to be consistent with ConnectTimeout.
  38. Rev 1.29 8/3/04 11:17:30 AM RLebeau
  39. Added support for ReadTimeout property
  40. Rev 1.28 8/2/04 5:50:58 PM RLebeau
  41. Added support for ConnectTimeout property
  42. Rev 1.27 2004.03.06 10:40:28 PM czhower
  43. Changed IOHandler management to fix bug in server shutdowns.
  44. Rev 1.26 2004.02.03 4:16:54 PM czhower
  45. For unit name changes.
  46. Rev 1.25 1/8/2004 8:22:54 PM JPMugaas
  47. SetIPVersion now virtual so I can override in TIdFTP. Other stuff may need
  48. the override as well.
  49. Rev 1.24 1/2/2004 12:02:18 AM BGooijen
  50. added OnBeforeBind/OnAfterBind
  51. Rev 1.23 12/31/2003 9:52:04 PM BGooijen
  52. Added IPv6 support
  53. Rev 1.20 2003.10.14 1:27:00 PM czhower
  54. Uupdates + Intercept support
  55. Rev 1.19 2003.10.01 9:11:26 PM czhower
  56. .Net
  57. Rev 1.18 2003.10.01 2:30:42 PM czhower
  58. .Net
  59. Rev 1.17 2003.10.01 11:16:36 AM czhower
  60. .Net
  61. Rev 1.16 2003.09.30 1:23:06 PM czhower
  62. Stack split for DotNet
  63. Rev 1.15 2003.09.18 2:59:46 PM czhower
  64. Modified port and host overrides to only override if values exist.
  65. Rev 1.14 6/3/2003 11:48:32 PM BGooijen
  66. Undid change from version 1.12, is now fixed in iohandlersocket
  67. Rev 1.13 2003.06.03 7:27:56 PM czhower
  68. Added overloaded Connect method
  69. Rev 1.12 5/23/2003 6:45:32 PM BGooijen
  70. ClosedGracefully is now set if Connect failes.
  71. Rev 1.11 2003.04.10 8:05:34 PM czhower
  72. removed unneeded self. reference
  73. Rev 1.10 4/7/2003 06:58:32 AM JPMugaas
  74. Implicit IOHandler now created in virtual method
  75. function TIdTCPClientCustom.MakeImplicitClientHandler: TIdIOHandler;
  76. Rev 1.9 3/17/2003 9:40:16 PM BGooijen
  77. Host and Port were not properly synchronised with the IOHandler, fixed that
  78. Rev 1.8 3/5/2003 11:05:24 PM BGooijen
  79. Intercept
  80. Rev 1.7 2003.02.25 1:36:16 AM czhower
  81. Rev 1.6 12-14-2002 22:52:34 BGooijen
  82. now also saves host and port settings when an explicit iohandler is used. the
  83. host and port settings are copied to the iohandler if the iohandler doesn't
  84. have them specified.
  85. Rev 1.5 12-14-2002 22:38:26 BGooijen
  86. The host and port settings were lost when the implicit iohandler was created
  87. in .Connect, fixed that.
  88. Rev 1.4 2002.12.07 12:26:12 AM czhower
  89. Rev 1.2 12/6/2002 02:11:42 PM JPMugaas
  90. Protected Port and Host properties added to TCPClient because those are
  91. needed by protocol implementations. Socket property added to TCPConnection.
  92. Rev 1.1 6/12/2002 4:08:34 PM SGrobety
  93. Rev 1.0 11/13/2002 09:00:26 AM JPMugaas
  94. }
  95. unit IdTCPClient;
  96. {$i IdCompilerDefines.inc}
  97. interface
  98. uses
  99. Classes,
  100. IdGlobal, IdExceptionCore, IdIOHandler, IdTCPConnection;
  101. (*$HPPEMIT '#if defined(_VCL_ALIAS_RECORDS)' *)
  102. (*$HPPEMIT '#if !defined(UNICODE)' *)
  103. (*$HPPEMIT '#pragma alias "@Idtcpclient@TIdTCPClientCustom@SetPortA$qqrxus"="@Idtcpclient@TIdTCPClientCustom@SetPort$qqrxus"' *)
  104. (*$HPPEMIT '#else' *)
  105. (*$HPPEMIT '#pragma alias "@Idtcpclient@TIdTCPClientCustom@SetPortW$qqrxus"="@Idtcpclient@TIdTCPClientCustom@SetPort$qqrxus"' *)
  106. (*$HPPEMIT '#endif' *)
  107. (*$HPPEMIT '#endif' *)
  108. type
  109. TIdTCPClientCustom = class(TIdTCPConnection)
  110. protected
  111. FBoundIP: String;
  112. FBoundPort: TIdPort;
  113. FBoundPortMax: TIdPort;
  114. FBoundPortMin: TIdPort;
  115. FConnectTimeout: Integer;
  116. FDestination: string;
  117. FHost: string;
  118. FIPVersion: TIdIPVersion;
  119. FOnConnected: TNotifyEvent;
  120. FPassword: string;
  121. FPort: TIdPort;
  122. FReadTimeout: Integer;
  123. FUsername: string;
  124. FReuseSocket: TIdReuseSocket;
  125. FUseNagle: Boolean;
  126. //
  127. FOnBeforeBind: TNotifyEvent;
  128. FOnAfterBind: TNotifyEvent;
  129. FOnSocketAllocated: TNotifyEvent;
  130. //
  131. procedure DoOnConnected; virtual;
  132. function MakeImplicitClientHandler: TIdIOHandler; virtual;
  133. //
  134. procedure SetConnectTimeout(const AValue: Integer);
  135. procedure SetReadTimeout(const AValue: Integer);
  136. procedure SetReuseSocket(const AValue: TIdReuseSocket);
  137. procedure SetUseNagle(const AValue: Boolean);
  138. procedure SetBoundIP(const AValue: String);
  139. procedure SetBoundPort(const AValue: TIdPort);
  140. procedure SetBoundPortMax(const AValue: TIdPort);
  141. procedure SetBoundPortMin(const AValue: TIdPort);
  142. procedure SetHost(const AValue: string); virtual;
  143. procedure SetPort(const AValue: TIdPort); virtual;
  144. procedure SetIPVersion(const AValue: TIdIPVersion); virtual;
  145. //
  146. procedure SetOnBeforeBind(const AValue: TNotifyEvent);
  147. procedure SetOnAfterBind(const AValue: TNotifyEvent);
  148. procedure SetOnSocketAllocated(const AValue: TNotifyEvent);
  149. //
  150. procedure SetIOHandler(AValue: TIdIOHandler); override;
  151. //
  152. function GetReadTimeout: Integer;
  153. function GetReuseSocket: TIdReuseSocket;
  154. function GetUseNagle: Boolean;
  155. //
  156. property Host: string read FHost write SetHost;
  157. property IPVersion: TIdIPVersion read FIPVersion write SetIPVersion;
  158. property Password: string read FPassword write FPassword;
  159. property Port: TIdPort read FPort write SetPort;
  160. property Username: string read FUsername write FUsername;
  161. public
  162. constructor Create(AOwner: TComponent); override;
  163. procedure Connect; overload; virtual;
  164. // This is overridden and not as default params so that descendants
  165. // do not have to worry about the arguments.
  166. // Also has been split further to allow usage from C# as it does not have optional
  167. // params
  168. procedure Connect(const AHost: string); overload;
  169. procedure Connect(const AHost: string; const APort: TIdPort); overload;
  170. function ConnectAndGetAll: string; virtual;
  171. //
  172. property BoundIP: string read FBoundIP write SetBoundIP;
  173. property BoundPort: TIdPort read FBoundPort write SetBoundPort default DEF_PORT_ANY;
  174. property BoundPortMax: TIdPort read FBoundPortMax write SetBoundPortMax default DEF_PORT_ANY;
  175. property BoundPortMin: TIdPort read FBoundPortMin write SetBoundPortMin default DEF_PORT_ANY;
  176. //
  177. property ConnectTimeout: Integer read FConnectTimeout write SetConnectTimeout;
  178. property ReadTimeout: Integer read GetReadTimeout write SetReadTimeout;
  179. property ReuseSocket: TIdReuseSocket read GetReuseSocket write SetReuseSocket default rsOSDependent;
  180. property UseNagle: Boolean read GetUseNagle write SetUseNagle default True;
  181. //
  182. property OnBeforeBind: TNotifyEvent read FOnBeforeBind write SetOnBeforeBind;
  183. property OnAfterBind: TNotifyEvent read FOnAfterBind write SetOnAfterBind;
  184. property OnSocketAllocated: TNotifyEvent read FOnSocketAllocated write SetOnSocketAllocated;
  185. //
  186. published
  187. property OnConnected: TNotifyEvent read FOnConnected write FOnConnected;
  188. end;
  189. TIdTCPClient = class(TIdTCPClientCustom)
  190. published
  191. property BoundIP;
  192. property BoundPort;
  193. property ConnectTimeout;
  194. property Host;
  195. property IPVersion default ID_DEFAULT_IP_VERSION;
  196. property Port;
  197. property ReadTimeout;
  198. property ReuseSocket;
  199. property UseNagle;
  200. property OnBeforeBind;
  201. property OnAfterBind;
  202. property OnSocketAllocated;
  203. end;
  204. //Temp IFDEF till we change aliaser
  205. // Temp - reversed it for code freeze - will rereverse later.
  206. implementation
  207. uses
  208. IdComponent, IdResourceStringsCore, IdIOHandlerSocket;
  209. { TIdTCPClientCustom }
  210. constructor TIdTCPClientCustom.Create(AOwner: TComponent);
  211. begin
  212. inherited Create(AOwner);
  213. FIPVersion := ID_DEFAULT_IP_VERSION;
  214. FReadTimeOut := IdTimeoutDefault;
  215. FBoundPort := DEF_PORT_ANY;
  216. FBoundPortMin := DEF_PORT_ANY;
  217. FBoundPortMax := DEF_PORT_ANY;
  218. FUseNagle := True;
  219. end;
  220. procedure TIdTCPClientCustom.Connect;
  221. var
  222. // under ARC, convert weak references to strong references before working with them
  223. LIOHandler: TIdIOHandler;
  224. LSocket: TIdIOHandlerSocket;
  225. LIntercept: TIdConnectionIntercept;
  226. begin
  227. if Connected then begin
  228. raise EIdAlreadyConnected.Create(RSAlreadyConnected);
  229. end;
  230. if Host = '' then begin
  231. raise EIdHostRequired.Create('A Host is required'); {do not localize}
  232. end;
  233. if Port = 0 then begin
  234. raise EIdPortRequired.Create('A Port is required'); {do not localize}
  235. end;
  236. LIOHandler := IOHandler;
  237. if LIOHandler = nil then begin
  238. LIOHandler := MakeImplicitClientHandler;
  239. IOHandler := LIOHandler;
  240. // TODO: always assign the OnStatus event even if the IOHandler is not implicit?
  241. LIOHandler.OnStatus := OnStatus; // TODO: assign DoStatus() instead of the handler directly...
  242. end;
  243. try
  244. // Bypass GetDestination
  245. if FDestination <> '' then begin
  246. LIOHandler.Destination := FDestination;
  247. end;
  248. {BGO: not any more, TIdTCPClientCustom has precedence now (for port protocols, and things like that)
  249. // We retain the settings that are in here (filled in by the user)
  250. // we only do this when the iohandler has no settings,
  251. // because the iohandler has precedence
  252. if (LIOHandler.Port = 0) and (LIOHandler.Host = '') then begin
  253. LIOHandler.Port := FPort;
  254. LIOHandler.Host := FHost;
  255. end;
  256. }
  257. LIOHandler.Port := FPort; //BGO: just to make sure
  258. LIOHandler.Host := FHost;
  259. LIOHandler.ConnectTimeout := FConnectTimeout;
  260. LIOHandler.ReadTimeout := FReadTimeout;
  261. LSocket := Socket;
  262. if LSocket <> nil then begin
  263. LSocket.BoundIP := FBoundIP;
  264. LSocket.BoundPort := FBoundPort;
  265. LSocket.BoundPortMin := FBoundPortMin;
  266. LSocket.BoundPortMax := FBoundPortMax;
  267. LSocket.IPVersion := FIPVersion;
  268. LSocket.ReuseSocket := FReuseSocket;
  269. LSocket.UseNagle := FUseNagle;
  270. LSocket.OnBeforeBind := FOnBeforeBind;
  271. LSocket.OnAfterBind := FOnAfterBind;
  272. LSocket.OnSocketAllocated := FOnSocketAllocated;
  273. {$IFDEF USE_OBJECT_ARC}LSocket := nil;{$ENDIF}
  274. end;
  275. LIOHandler.Open;
  276. LIntercept := LIOHandler.Intercept;
  277. if LIntercept <> nil then begin
  278. LIntercept.Connect(Self);
  279. {$IFDEF USE_OBJECT_ARC}LIntercept := nil;{$ENDIF}
  280. end;
  281. DoStatus(hsConnected, [Host]);
  282. DoOnConnected;
  283. except
  284. if LIOHandler <> nil then begin
  285. LIOHandler.Close;
  286. if LIOHandler.Owner = Self then begin
  287. {$IFDEF USE_OBJECT_ARC}LIOHandler := nil;{$ENDIF}
  288. SetIOHandler(nil); // RLebeau - will free the implicit IOHandler
  289. end;
  290. end;
  291. raise;
  292. end;
  293. end;
  294. function TIdTCPClientCustom.ConnectAndGetAll: string;
  295. begin
  296. Connect; try
  297. Result := IOHandler.AllData;
  298. finally Disconnect; end;
  299. end;
  300. procedure TIdTCPClientCustom.DoOnConnected;
  301. begin
  302. if Assigned(OnConnected) then begin
  303. OnConnected(Self);
  304. end;
  305. end;
  306. procedure TIdTCPClientCustom.SetConnectTimeout(const AValue: Integer);
  307. begin
  308. FConnectTimeout := AValue;
  309. if IOHandler <> nil then begin
  310. IOHandler.ConnectTimeout := AValue;
  311. end;
  312. end;
  313. procedure TIdTCPClientCustom.SetReadTimeout(const AValue: Integer);
  314. begin
  315. FReadTimeout := AValue;
  316. if IOHandler <> nil then begin
  317. IOHandler.ReadTimeout := AValue;
  318. end;
  319. end;
  320. procedure TIdTCPClientCustom.SetReuseSocket(const AValue: TIdReuseSocket);
  321. begin
  322. FReuseSocket := AValue;
  323. if Socket <> nil then begin
  324. Socket.ReuseSocket := AValue;
  325. end;
  326. end;
  327. procedure TIdTCPClientCustom.SetUseNagle(const AValue: Boolean);
  328. begin
  329. FUseNagle := AValue;
  330. if Socket <> nil then begin
  331. Socket.UseNagle := AValue;
  332. end;
  333. end;
  334. procedure TIdTCPClientCustom.SetBoundIP(const AValue: String);
  335. begin
  336. FBoundIP := AValue;
  337. if Socket <> nil then begin
  338. Socket.BoundIP := AValue;
  339. end;
  340. end;
  341. procedure TIdTCPClientCustom.SetBoundPort(const AValue: TIdPort);
  342. begin
  343. FBoundPort := AValue;
  344. if Socket <> nil then begin
  345. Socket.BoundPort := AValue;
  346. end;
  347. end;
  348. procedure TIdTCPClientCustom.SetBoundPortMax(const AValue: TIdPort);
  349. begin
  350. FBoundPortMax := AValue;
  351. if Socket <> nil then begin
  352. Socket.BoundPortMax := AValue;
  353. end;
  354. end;
  355. procedure TIdTCPClientCustom.SetBoundPortMin(const AValue: TIdPort);
  356. begin
  357. FBoundPortMin := AValue;
  358. if Socket <> nil then begin
  359. Socket.BoundPortMin := AValue;
  360. end;
  361. end;
  362. procedure TIdTCPClientCustom.SetHost(const AValue: string);
  363. begin
  364. FHost := AValue;
  365. if IOHandler <> nil then begin
  366. IOHandler.Host := AValue;
  367. end;
  368. end;
  369. procedure TIdTCPClientCustom.SetPort(const AValue: TIdPort);
  370. begin
  371. FPort := AValue;
  372. if IOHandler <> nil then begin
  373. IOHandler.Port := AValue;
  374. end;
  375. end;
  376. procedure TIdTCPClientCustom.SetIPVersion(const AValue: TIdIPVersion);
  377. begin
  378. FIPVersion := AValue;
  379. if Socket <> nil then begin
  380. Socket.IPVersion := AValue;
  381. end;
  382. end;
  383. procedure TIdTCPClientCustom.SetOnBeforeBind(const AValue: TNotifyEvent);
  384. begin
  385. FOnBeforeBind := AValue;
  386. if Socket <> nil then begin
  387. Socket.OnBeforeBind := AValue;
  388. end;
  389. end;
  390. procedure TIdTCPClientCustom.SetOnAfterBind(const AValue: TNotifyEvent);
  391. begin
  392. FOnAfterBind := AValue;
  393. if Socket <> nil then begin
  394. Socket.OnAfterBind := AValue;
  395. end;
  396. end;
  397. procedure TIdTCPClientCustom.SetOnSocketAllocated(const AValue: TNotifyEvent);
  398. begin
  399. FOnSocketAllocated := AValue;
  400. if Socket <> nil then begin
  401. Socket.OnSocketAllocated := AValue;
  402. end;
  403. end;
  404. procedure TIdTCPClientCustom.SetIOHandler(AValue: TIdIOHandler);
  405. begin
  406. inherited SetIOHandler(AValue);
  407. // TIdTCPClientCustom overrides settings in iohandler to initialize
  408. // protocol defaults.
  409. if IOHandler <> nil then begin
  410. IOHandler.Port := FPort;
  411. IOHandler.Host := FHost;
  412. IOHandler.ConnectTimeout := FConnectTimeout;
  413. IOHandler.ReadTimeout := FReadTimeout;
  414. end;
  415. if Socket <> nil then begin
  416. Socket.BoundIP := FBoundIP;
  417. Socket.BoundPort := FBoundPort;
  418. Socket.BoundPortMin := FBoundPortMin;
  419. Socket.BoundPortMax := FBoundPortMax;
  420. Socket.IPVersion := FIPVersion;
  421. Socket.ReuseSocket := FReuseSocket;
  422. Socket.UseNagle := FUseNagle;
  423. // TODO: use local event handlers that then trigger the user event handler if assigned
  424. Socket.OnBeforeBind := FOnBeforeBind;
  425. Socket.OnAfterBind := FOnAfterBind;
  426. Socket.OnSocketAllocated := FOnSocketAllocated;
  427. end;
  428. end;
  429. function TIdTCPClientCustom.MakeImplicitClientHandler: TIdIOHandler;
  430. begin
  431. Result := TIdIOHandler.MakeDefaultIOHandler(Self);
  432. end;
  433. procedure TIdTCPClientCustom.Connect(const AHost: string);
  434. begin
  435. Host := AHost;
  436. Connect;
  437. end;
  438. procedure TIdTCPClientCustom.Connect(const AHost: string; const APort: TIdPort);
  439. begin
  440. Host := AHost;
  441. Port := APort;
  442. Connect;
  443. end;
  444. function TIdTCPClientCustom.GetReadTimeout: Integer;
  445. begin
  446. if IOHandler <> nil then begin
  447. Result := IOHandler.ReadTimeout;
  448. end else begin
  449. Result := FReadTimeout;
  450. end;
  451. end;
  452. function TIdTCPClientCustom.GetReuseSocket: TIdReuseSocket;
  453. begin
  454. if Socket <> nil then begin
  455. Result := Socket.ReuseSocket;
  456. end else begin
  457. Result := FReuseSocket;
  458. end;
  459. end;
  460. function TIdTCPClientCustom.GetUseNagle: Boolean;
  461. begin
  462. if Socket <> nil then begin
  463. Result := Socket.UseNagle;
  464. end else begin
  465. Result := FUseNagle;
  466. end;
  467. end;
  468. end.