IdSimpleServer.pas 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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.17 7/13/04 6:46:36 PM RLebeau
  18. Added support for BoundPortMin/Max propeties
  19. }
  20. {
  21. Rev 1.16 6/6/2004 12:49:40 PM JPMugaas
  22. Removed old todo's for things that have already been done.
  23. }
  24. {
  25. Rev 1.15 5/6/2004 6:04:44 PM JPMugaas
  26. Attempt to reenable TransparentProxy.Bind.
  27. }
  28. {
  29. Rev 1.14 5/5/2004 2:08:40 PM JPMugaas
  30. Reenabled Socks Listen for TIdSimpleServer.
  31. }
  32. {
  33. Rev 1.13 2004.02.03 4:16:52 PM czhower
  34. For unit name changes.
  35. }
  36. {
  37. Rev 1.12 2004.01.20 10:03:34 PM czhower
  38. InitComponent
  39. }
  40. {
  41. Rev 1.11 1/2/2004 12:02:16 AM BGooijen
  42. added OnBeforeBind/OnAfterBind
  43. }
  44. {
  45. Rev 1.10 1/1/2004 10:57:58 PM BGooijen
  46. Added IPv6 support
  47. }
  48. {
  49. Rev 1.9 10/26/2003 10:08:44 PM BGooijen
  50. Compiles in DotNet
  51. }
  52. {
  53. Rev 1.8 10/20/2003 03:04:56 PM JPMugaas
  54. Should now work without Transparant Proxy. That still needs to be enabled.
  55. }
  56. {
  57. Rev 1.7 2003.10.14 9:57:42 PM czhower
  58. Compile todos
  59. }
  60. {
  61. Rev 1.6 2003.10.11 5:50:12 PM czhower
  62. -VCL fixes for servers
  63. -Chain suport for servers (Super core)
  64. -Scheduler upgrades
  65. -Full yarn support
  66. }
  67. {
  68. Rev 1.5 2003.09.30 1:23:02 PM czhower
  69. Stack split for DotNet
  70. }
  71. {
  72. Rev 1.4 5/16/2003 9:25:36 AM BGooijen
  73. TransparentProxy support
  74. }
  75. {
  76. Rev 1.3 3/29/2003 5:55:04 PM BGooijen
  77. now calls AfterAccept
  78. }
  79. {
  80. Rev 1.2 3/23/2003 11:24:46 PM BGooijen
  81. changed cast from TIdIOHandlerStack to TIdIOHandlerSocket
  82. }
  83. {
  84. Rev 1.1 1-6-2003 21:39:00 BGooijen
  85. The handle to the listening socket was not closed when accepting a
  86. connection. This is fixed by merging the responsible code from 9.00.11
  87. Rev 1.0 11/13/2002 08:58:40 AM JPMugaas
  88. }
  89. unit IdSimpleServer;
  90. interface
  91. {$i IdCompilerDefines.inc}
  92. uses
  93. Classes,
  94. IdException,
  95. IdGlobal,
  96. IdSocketHandle,
  97. IdTCPConnection,
  98. IdStackConsts,
  99. IdIOHandler;
  100. const
  101. ID_ACCEPT_WAIT = 1000;
  102. type
  103. TIdSimpleServer = class(TIdTCPConnection)
  104. protected
  105. FAbortedRequested: Boolean;
  106. FAcceptWait: Integer;
  107. FBoundIP: String;
  108. FBoundPort: TIdPort;
  109. FBoundPortMin: TIdPort;
  110. FBoundPortMax: TIdPort;
  111. FIPVersion: TIdIPVersion;
  112. FListenHandle: TIdStackSocketHandle;
  113. FListening: Boolean;
  114. FOnBeforeBind: TNotifyEvent;
  115. FOnAfterBind: TNotifyEvent;
  116. //
  117. procedure Bind;
  118. procedure DoBeforeBind; virtual;
  119. procedure DoAfterBind; virtual;
  120. function GetBinding: TIdSocketHandle;
  121. procedure SetIOHandler(AValue: TIdIOHandler); override;
  122. procedure SetIPVersion(const AValue: TIdIPVersion);
  123. public
  124. constructor Create(AOwner: TComponent); override;
  125. //
  126. procedure Abort; virtual;
  127. procedure BeginListen; virtual;
  128. procedure CreateBinding;
  129. procedure EndListen; virtual;
  130. procedure Listen(ATimeout: Integer = IdTimeoutDefault); virtual;
  131. //
  132. property AcceptWait: Integer read FAcceptWait write FAcceptWait default ID_ACCEPT_WAIT;
  133. published
  134. property BoundIP: string read FBoundIP write FBoundIP;
  135. property BoundPort: TIdPort read FBoundPort write FBoundPort;
  136. property BoundPortMin: TIdPort read FBoundPortMin write FBoundPortMin;
  137. property BoundPortMax: TIdPort read FBoundPortMax write FBoundPortMax;
  138. property Binding: TIdSocketHandle read GetBinding;
  139. property IPVersion: TIdIPVersion read FIPVersion write SetIPVersion default ID_DEFAULT_IP_VERSION;
  140. property OnBeforeBind: TNotifyEvent read FOnBeforeBind write FOnBeforeBind;
  141. property OnAfterBind: TNotifyEvent read FOnAfterBind write FOnAfterBind;
  142. end;
  143. EIdCannotUseNonSocketIOHandler = class(EIdException);
  144. implementation
  145. uses
  146. IdExceptionCore,
  147. IdIOHandlerStack,
  148. IdIOHandlerSocket,
  149. IdCustomTransparentProxy,
  150. IdResourceStringsCore,
  151. IdStack;
  152. { TIdSimpleServer }
  153. constructor TIdSimpleServer.Create(AOwner: TComponent);
  154. begin
  155. inherited Create(AOwner);
  156. FIPVersion := ID_DEFAULT_IP_VERSION;
  157. FAcceptWait := ID_ACCEPT_WAIT;
  158. FListenHandle := Id_INVALID_SOCKET;
  159. end;
  160. procedure TIdSimpleServer.Abort;
  161. begin
  162. FAbortedRequested := True;
  163. end;
  164. procedure TIdSimpleServer.BeginListen;
  165. var
  166. // under ARC, convert a weak reference to a strong reference before working with it
  167. LProxy: TIdCustomTransparentProxy;
  168. begin
  169. // Must be before IOHandler as it resets it
  170. EndListen;
  171. CreateBinding;
  172. LProxy := Socket.TransparentProxy;
  173. if LProxy.Enabled then begin
  174. Socket.Binding.IP := BoundIP;
  175. LProxy.Bind(FIOHandler, BoundPort);
  176. end else begin
  177. Bind;
  178. Binding.Listen(1);
  179. end;
  180. FListening := True;
  181. end;
  182. procedure TIdSimpleServer.Bind;
  183. var
  184. LBinding: TIdSocketHandle;
  185. begin
  186. LBinding := Binding;
  187. try
  188. DoBeforeBind;
  189. LBinding.IPVersion := FIPVersion; // needs to be before AllocateSocket, because AllocateSocket uses this
  190. LBinding.AllocateSocket;
  191. FListenHandle := LBinding.Handle;
  192. LBinding.IP := BoundIP;
  193. LBinding.Port := BoundPort;
  194. LBinding.ClientPortMin := BoundPortMin;
  195. LBinding.ClientPortMax := BoundPortMax;
  196. LBinding.Bind;
  197. DoAfterBind;
  198. except
  199. FListenHandle := Id_INVALID_SOCKET;
  200. raise;
  201. end;
  202. end;
  203. procedure TIdSimpleServer.CreateBinding;
  204. begin
  205. if not Assigned(IOHandler) then begin
  206. CreateIOHandler();
  207. end;
  208. IOHandler.Open;
  209. end;
  210. procedure TIdSimpleServer.DoBeforeBind;
  211. begin
  212. if Assigned(FOnBeforeBind) then begin
  213. FOnBeforeBind(self);
  214. end;
  215. end;
  216. procedure TIdSimpleServer.DoAfterBind;
  217. begin
  218. if Assigned(FOnAfterBind) then begin
  219. FOnAfterBind(self);
  220. end;
  221. end;
  222. procedure TIdSimpleServer.EndListen;
  223. begin
  224. FAbortedRequested := False;
  225. FListening := False;
  226. end;
  227. function TIdSimpleServer.GetBinding: TIdSocketHandle;
  228. begin
  229. if Assigned(Socket) then begin
  230. Result := Socket.Binding;
  231. end else begin
  232. Result := nil;
  233. end;
  234. end;
  235. procedure TIdSimpleServer.SetIOHandler(AValue: TIdIOHandler);
  236. begin
  237. if Assigned(AValue) then begin
  238. if not (AValue is TIdIOHandlerSocket) then begin
  239. raise EIdCannotUseNonSocketIOHandler.Create(RSCannotUseNonSocketIOHandler);
  240. end;
  241. end;
  242. inherited SetIOHandler(AValue);
  243. end;
  244. procedure TIdSimpleServer.SetIPVersion(const AValue: TIdIPVersion);
  245. begin
  246. FIPVersion := AValue;
  247. if Assigned(Socket) then begin
  248. Socket.IPVersion := AValue;
  249. end;
  250. end;
  251. procedure TIdSimpleServer.Listen(ATimeout: Integer = IdTimeoutDefault);
  252. var
  253. // under ARC, convert a weak reference to a strong reference before working with it
  254. LProxy: TIdCustomTransparentProxy;
  255. LAccepted: Boolean;
  256. function DoListenTimeout(ALTimeout: Integer; AUseProxy: Boolean): Boolean;
  257. var
  258. LSleepTime: Integer;
  259. begin
  260. LSleepTime := AcceptWait;
  261. if ALTimeout = IdTimeoutDefault then begin
  262. ALTimeout := IdTimeoutInfinite;
  263. end;
  264. if ALTimeout = IdTimeoutInfinite then begin
  265. repeat
  266. if AUseProxy then begin
  267. Result := LProxy.Listen(IOHandler, LSleepTime);
  268. end else begin
  269. Result := Binding.Select(LSleepTime);
  270. end;
  271. until Result or FAbortedRequested;
  272. Exit;
  273. end;
  274. while ALTimeout > LSleepTime do begin
  275. if AUseProxy then begin
  276. Result := LProxy.Listen(IOHandler, LSleepTime);
  277. end else begin
  278. Result := Binding.Select(LSleepTime);
  279. end;
  280. if Result or FAbortedRequested then begin
  281. Exit;
  282. end;
  283. Dec(ALTimeout, LSleepTime);
  284. end;
  285. if AUseProxy then begin
  286. Result := LProxy.Listen(IOHandler, ALTimeout);
  287. end else begin
  288. Result := Binding.Select(ALTimeout);
  289. end;
  290. end;
  291. begin
  292. if not FListening then begin
  293. BeginListen;
  294. end;
  295. LProxy := Socket.TransparentProxy;
  296. if LProxy.Enabled then begin
  297. LAccepted := DoListenTimeout(ATimeout, True);
  298. end else
  299. begin
  300. LAccepted := DoListenTimeout(ATimeout, False);
  301. if LAccepted then begin
  302. if Binding.Accept(Binding.Handle) then begin
  303. IOHandler.AfterAccept;
  304. end;
  305. end;
  306. // This is now protected. Disconnect replaces it - but it also calls shutdown.
  307. // Im not sure we want to call shutdown here? Need to investigate before fixing
  308. // this.
  309. GStack.Disconnect(FListenHandle);
  310. FListenHandle := Id_INVALID_SOCKET;
  311. end;
  312. if not LAccepted then begin
  313. raise EIdAcceptTimeout.Create(RSAcceptTimeout);
  314. end;
  315. end;
  316. end.