IdMappedPortTCP.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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.28 12/2/2004 4:23:54 PM JPMugaas
  18. Adjusted for changes in Core.
  19. Rev 1.27 11/15/04 11:32:22 AM RLebeau
  20. Changed OutboundConnect() to assign the TIdTcpClient.ConnectTimeout property
  21. instead of the IOHandler.ConnectTimeout property.
  22. Rev 1.26 10/6/2004 10:22:12 PM BGooijen
  23. Removed PEVerify errors in this unit
  24. Rev 1.25 8/2/04 5:55:00 PM RLebeau
  25. Updated TIdMappedPortContext.OutboundConnect() with ConnectTimeout property
  26. change.
  27. Rev 1.24 3/1/04 7:17:02 PM RLebeau
  28. Minor correction to previous change
  29. Rev 1.23 3/1/04 7:14:34 PM RLebeau
  30. Updated TIdMappedPortContext.OutboundConnect() to call CreateIOHandler()
  31. before attempting to use the outbound client's IOHandler property.
  32. Rev 1.22 2004.02.03 5:43:58 PM czhower
  33. Name changes
  34. Rev 1.21 2/1/2004 4:23:32 AM JPMugaas
  35. Should now compile in DotNET.
  36. Rev 1.20 1/21/2004 3:11:30 PM JPMugaas
  37. InitComponent
  38. Rev 1.19 12/14/03 7:16:20 PM RLebeau
  39. Typo fixes when accessing OutboudClient.IOHandler
  40. Rev 1.18 2003.11.29 10:19:04 AM czhower
  41. Updated for core change to InputBuffer.
  42. Rev 1.17 2003.10.21 9:13:10 PM czhower
  43. Now compiles.
  44. Rev 1.16 10/19/2003 5:25:10 PM DSiders
  45. Added localization comments.
  46. Rev 1.15 2003.10.18 9:42:10 PM czhower
  47. Boatload of bug fixes to command handlers.
  48. Rev 1.14 2003.10.12 4:04:00 PM czhower
  49. compile todos
  50. Rev 1.13 9/19/2003 03:30:06 PM JPMugaas
  51. Now should compile again.
  52. Rev 1.12 04.06.2003 14:09:28 ARybin
  53. updated for new IoHandler behavior
  54. Rev 1.11 3/6/2003 5:08:46 PM SGrobety
  55. Updated the read buffer methodes to fit the new core (InputBuffer ->
  56. InputBufferAsString + call to CheckForDataOnSource)
  57. Rev 1.10 28.05.2003 17:35:34 ARybin
  58. right bug fix
  59. Rev 1.9 28.05.2003 16:55:30 ARybin
  60. bug fix
  61. Rev 1.8 5/26/2003 12:23:46 PM JPMugaas
  62. Rev 1.7 4/3/2003 7:26:10 PM BGooijen
  63. Re-enabled .ConnectTimeout and .Connect
  64. Rev 1.6 3/21/2003 11:45:36 AM JPMugaas
  65. Added OnBeforeConnect method so the TIdMappedPort component is more flexible.
  66. Rev 1.5 2/24/2003 09:14:38 PM JPMugaas
  67. Rev 1.4 1/20/2003 1:15:32 PM BGooijen
  68. Changed to TIdTCPServer / TIdCmdTCPServer classes
  69. Rev 1.3 1/17/2003 06:45:12 PM JPMugaas
  70. Now compiles with new framework.
  71. Rev 1.2 1-8-2003 22:20:40 BGooijen
  72. these compile (TIdContext)
  73. Rev 1.1 12/7/2002 06:43:10 PM JPMugaas
  74. These should now compile except for Socks server. IPVersion has to be a
  75. property someplace for that.
  76. Rev 1.0 11/13/2002 07:56:42 AM JPMugaas
  77. 2001-12-xx - Andrew P.Rybin
  78. -new architecture
  79. 2002-02-02 - Andrew P.Rybin
  80. -DoDisconnect fix
  81. }
  82. unit IdMappedPortTCP;
  83. interface
  84. {$i IdCompilerDefines.inc}
  85. uses
  86. Classes,
  87. IdContext,
  88. IdCustomTCPServer,
  89. IdGlobal, IdStack, IdTCPConnection, IdYarn, SysUtils;
  90. type
  91. TIdMappedPortTCP = class;
  92. TIdMappedPortContext = class(TIdServerContext)
  93. protected
  94. FOutboundClient: TIdTCPConnection;//was TIdTCPClient
  95. FReadList: TIdSocketList;
  96. FDataAvailList: TIdSocketList;
  97. FConnectTimeOut: Integer;
  98. FNetData: TIdBytes;
  99. FServer : TIdMappedPortTCP;
  100. //
  101. procedure CheckForData(DoRead: Boolean); virtual;
  102. procedure HandleLocalClientData; virtual;
  103. procedure HandleOutboundClientData; virtual;
  104. procedure OutboundConnect; virtual;
  105. public
  106. constructor Create(
  107. AConnection: TIdTCPConnection;
  108. AYarn: TIdYarn;
  109. AList: TIdContextThreadList = nil
  110. ); override;
  111. destructor Destroy; override;
  112. //
  113. property Server : TIdMappedPortTCP Read FServer write FServer;
  114. property ConnectTimeOut: Integer read FConnectTimeOut write FConnectTimeOut default IdTimeoutDefault;
  115. property NetData: TIdBytes read FNetData write FNetData;
  116. property OutboundClient: TIdTCPConnection read FOutboundClient write FOutboundClient;
  117. end;//TIdMappedPortContext
  118. TIdMappedPortTCP = class(TIdCustomTCPServer)
  119. protected
  120. FMappedHost: string;
  121. FMappedPort: TIdPort;
  122. FOnBeforeConnect: TIdServerThreadEvent;
  123. //AThread.Connection.Server & AThread.OutboundClient
  124. FOnOutboundConnect: TIdServerThreadEvent;
  125. FOnOutboundData: TIdServerThreadEvent;
  126. FOnOutboundDisConnect: TIdServerThreadEvent;
  127. //
  128. procedure DoBeforeConnect(AContext: TIdContext); virtual;
  129. procedure DoConnect(AContext: TIdContext); override;
  130. function DoExecute(AContext: TIdContext): boolean; override;
  131. procedure DoDisconnect(AContext: TIdContext); override; //DoLocalClientDisconnect
  132. procedure DoLocalClientConnect(AContext: TIdContext); virtual;
  133. procedure DoLocalClientData(AContext: TIdContext); virtual;//APR: bServer
  134. procedure DoOutboundClientConnect(AContext: TIdContext); virtual;
  135. procedure DoOutboundClientData(AContext: TIdContext); virtual;
  136. procedure DoOutboundDisconnect(AContext: TIdContext); virtual;
  137. function GetOnConnect: TIdServerThreadEvent;
  138. function GetOnExecute: TIdServerThreadEvent;
  139. procedure SetOnConnect(const Value: TIdServerThreadEvent);
  140. procedure SetOnExecute(const Value: TIdServerThreadEvent);
  141. function GetOnDisconnect: TIdServerThreadEvent;
  142. procedure SetOnDisconnect(const Value: TIdServerThreadEvent);
  143. procedure InitComponent; override;
  144. published
  145. property OnBeforeConnect: TIdServerThreadEvent read FOnBeforeConnect write FOnBeforeConnect;
  146. property MappedHost: String read FMappedHost write FMappedHost;
  147. property MappedPort: TIdPort read FMappedPort write FMappedPort;
  148. //
  149. property OnConnect: TIdServerThreadEvent read GetOnConnect write SetOnConnect; //OnLocalClientConnect
  150. property OnOutboundConnect: TIdServerThreadEvent read FOnOutboundConnect write FOnOutboundConnect;
  151. property OnExecute: TIdServerThreadEvent read GetOnExecute write SetOnExecute;//OnLocalClientData
  152. property OnOutboundData: TIdServerThreadEvent read FOnOutboundData write FOnOutboundData;
  153. property OnDisconnect: TIdServerThreadEvent read GetOnDisconnect write SetOnDisconnect;//OnLocalClientDisconnect
  154. property OnOutboundDisconnect: TIdServerThreadEvent read FOnOutboundDisconnect write FOnOutboundDisconnect;
  155. End;//TIdMappedPortTCP
  156. Implementation
  157. uses
  158. IdIOHandler, IdIOHandlerSocket, IdTCPClient;
  159. procedure TIdMappedPortTCP.InitComponent;
  160. begin
  161. inherited InitComponent;
  162. FContextClass := TIdMappedPortContext;
  163. end;
  164. procedure TIdMappedPortTCP.DoBeforeConnect(AContext: TIdContext);
  165. begin
  166. if Assigned(FOnBeforeConnect) then begin
  167. FOnBeforeConnect(AContext);
  168. end;
  169. end;
  170. procedure TIdMappedPortTCP.DoLocalClientConnect(AContext: TIdContext);
  171. begin
  172. if Assigned(FOnConnect) then begin
  173. FOnConnect(AContext);
  174. end;
  175. end;
  176. procedure TIdMappedPortTCP.DoOutboundClientConnect(AContext: TIdContext);
  177. begin
  178. if Assigned(FOnOutboundConnect) then begin
  179. FOnOutboundConnect(AContext);
  180. end;
  181. end;
  182. procedure TIdMappedPortTCP.DoLocalClientData(AContext: TIdContext);
  183. begin
  184. if Assigned(FOnExecute) then begin
  185. FOnExecute(AContext);
  186. end;
  187. end;
  188. procedure TIdMappedPortTCP.DoOutboundClientData(AContext: TIdContext);
  189. begin
  190. if Assigned(FOnOutboundData) then begin
  191. FOnOutboundData(AContext);
  192. end;
  193. end;
  194. procedure TIdMappedPortTCP.DoDisconnect(AContext: TIdContext);
  195. begin
  196. inherited DoDisconnect(AContext);
  197. //check for loop
  198. if Assigned(TIdMappedPortContext(AContext).FOutboundClient) and
  199. TIdMappedPortContext(AContext).FOutboundClient.Connected then
  200. begin
  201. TIdMappedPortContext(AContext).FOutboundClient.Disconnect;
  202. end;
  203. end;
  204. procedure TIdMappedPortTCP.DoOutboundDisconnect(AContext: TIdContext);
  205. begin
  206. if Assigned(FOnOutboundDisconnect) then begin
  207. FOnOutboundDisconnect(AContext);
  208. end;
  209. AContext.Connection.Disconnect; //disconnect local
  210. end;
  211. procedure TIdMappedPortTCP.DoConnect(AContext: TIdContext);
  212. var
  213. LContext: TIdMappedPortContext;
  214. begin
  215. DoBeforeConnect(AContext);
  216. LContext := TIdMappedPortContext(AContext);
  217. //WARNING: Check TIdTCPServer.DoConnect and synchronize code. Don't call inherited!=> OnConnect in OutboundConnect {Do not Localize}
  218. LContext.OutboundConnect;
  219. //cache
  220. LContext.FReadList.Clear;
  221. LContext.FReadList.Add(AContext.Binding.Handle);
  222. LContext.FReadList.Add(LContext.FOutboundClient.Socket.Binding.Handle);
  223. end;
  224. function TIdMappedPortTCP.DoExecute(AContext: TIdContext): Boolean;
  225. var
  226. LContext: TIdMappedPortContext;
  227. begin
  228. LContext := TIdMappedPortContext(AContext);
  229. try
  230. LContext.CheckForData(True);
  231. finally
  232. if not LContext.FOutboundClient.Connected then begin
  233. Result := False;
  234. DoOutboundDisconnect(AContext); //&Connection.Disconnect
  235. end else begin;
  236. Result := AContext.Connection.Connected;
  237. end;
  238. end;
  239. end;
  240. function TIdMappedPortTCP.GetOnConnect: TIdServerThreadEvent;
  241. begin
  242. Result := FOnConnect;
  243. end;
  244. function TIdMappedPortTCP.GetOnExecute: TIdServerThreadEvent;
  245. begin
  246. Result := FOnExecute;
  247. end;
  248. function TIdMappedPortTCP.GetOnDisconnect: TIdServerThreadEvent;
  249. begin
  250. Result := FOnDisconnect;
  251. end;
  252. procedure TIdMappedPortTCP.SetOnConnect(const Value: TIdServerThreadEvent);
  253. begin
  254. FOnConnect := Value;
  255. end;
  256. procedure TIdMappedPortTCP.SetOnExecute(const Value: TIdServerThreadEvent);
  257. begin
  258. FOnExecute := Value;
  259. end;
  260. procedure TIdMappedPortTCP.SetOnDisconnect(const Value: TIdServerThreadEvent);
  261. begin
  262. FOnDisconnect := Value;
  263. end;
  264. { TIdMappedPortContext }
  265. constructor TIdMappedPortContext.Create(
  266. AConnection: TIdTCPConnection;
  267. AYarn: TIdYarn;
  268. AList: TIdContextThreadList = nil
  269. );
  270. begin
  271. inherited Create(AConnection, AYarn, AList);
  272. FReadList := TIdSocketList.CreateSocketList;
  273. FDataAvailList := TIdSocketList.CreateSocketList;
  274. FConnectTimeOut := IdTimeoutDefault;
  275. end;
  276. destructor TIdMappedPortContext.Destroy;
  277. begin
  278. FreeAndNil(FOutboundClient);
  279. FreeAndNIL(FReadList);
  280. FreeAndNIL(FDataAvailList);
  281. inherited Destroy;
  282. end;
  283. procedure TIdMappedPortContext.CheckForData(DoRead: Boolean);
  284. begin
  285. if DoRead and Connection.IOHandler.InputBufferIsEmpty and FOutboundClient.IOHandler.InputBufferIsEmpty then
  286. begin
  287. if FReadList.SelectReadList(FDataAvailList, IdTimeoutInfinite) then
  288. begin
  289. //1.LConnectionHandle
  290. if FDataAvailList.ContainsSocket(Connection.Socket.Binding.Handle) then
  291. begin
  292. // TODO: WSAECONNRESET (Exception [EIdSocketError] Socket Error # 10054 Connection reset by peer)
  293. Connection.IOHandler.CheckForDataOnSource(0);
  294. end;
  295. //2.LOutBoundHandle
  296. if FDataAvailList.ContainsSocket(FOutboundClient.Socket.Binding.Handle) then
  297. begin
  298. FOutboundClient.IOHandler.CheckForDataOnSource(0);
  299. end;
  300. end;
  301. end;
  302. if not Connection.IOHandler.InputBufferIsEmpty then
  303. begin
  304. HandleLocalClientData;
  305. end;
  306. if not FOutboundClient.IOHandler.InputBufferIsEmpty then
  307. begin
  308. HandleOutboundClientData;
  309. end;
  310. Connection.IOHandler.CheckForDisconnect;
  311. FOutboundClient.IOHandler.CheckForDisconnect;
  312. end;
  313. procedure TIdMappedPortContext.HandleLocalClientData;
  314. begin
  315. SetLength(FNetData, 0);
  316. Connection.IOHandler.InputBuffer.ExtractToBytes(FNetData);
  317. Server.DoLocalClientData(Self);
  318. FOutboundClient.IOHandler.Write(FNetData);
  319. end;
  320. procedure TIdMappedPortContext.HandleOutboundClientData;
  321. begin
  322. SetLength(FNetData, 0);
  323. FOutboundClient.IOHandler.InputBuffer.ExtractToBytes(FNetData);
  324. Server.DoOutboundClientData(Self);
  325. Connection.IOHandler.Write(FNetData);
  326. end;
  327. procedure TIdMappedPortContext.OutboundConnect;
  328. var
  329. LServer: TIdMappedPortTCP;
  330. LClient: TIdTCPClient;
  331. begin
  332. FOutboundClient := TIdTCPClient.Create(nil);
  333. LServer := TIdMappedPortTCP(Server);
  334. try
  335. LClient := TIdTCPClient(FOutboundClient);
  336. LClient.Port := LServer.MappedPort;
  337. LClient.Host := LServer.MappedHost;
  338. LServer.DoLocalClientConnect(Self);
  339. LClient.ConnectTimeout := FConnectTimeOut;
  340. LClient.Connect;
  341. LServer.DoOutboundClientConnect(Self);
  342. //APR: buffer can contain data from prev (users) read op.
  343. CheckForData(False);
  344. except
  345. on E: Exception do
  346. begin
  347. DoException(E);// DONE: Handle connect failures
  348. Connection.Disconnect; //req IdTcpServer with "Stop this thread if we were disconnected"
  349. raise;
  350. end;
  351. end;
  352. end;
  353. end.