IdSimpleServer.pas 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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 InitComponent; override;
  122. procedure SetIOHandler(AValue: TIdIOHandler); override;
  123. procedure SetIPVersion(const AValue: TIdIPVersion);
  124. public
  125. procedure Abort; virtual;
  126. procedure BeginListen; virtual;
  127. procedure CreateBinding;
  128. procedure EndListen; virtual;
  129. procedure Listen(ATimeout: Integer = IdTimeoutDefault); virtual;
  130. //
  131. property AcceptWait: Integer read FAcceptWait write FAcceptWait default ID_ACCEPT_WAIT;
  132. published
  133. property BoundIP: string read FBoundIP write FBoundIP;
  134. property BoundPort: TIdPort read FBoundPort write FBoundPort;
  135. property BoundPortMin: TIdPort read FBoundPortMin write FBoundPortMin;
  136. property BoundPortMax: TIdPort read FBoundPortMax write FBoundPortMax;
  137. property Binding: TIdSocketHandle read GetBinding;
  138. property IPVersion: TIdIPVersion read FIPVersion write SetIPVersion default ID_DEFAULT_IP_VERSION;
  139. property OnBeforeBind: TNotifyEvent read FOnBeforeBind write FOnBeforeBind;
  140. property OnAfterBind: TNotifyEvent read FOnAfterBind write FOnAfterBind;
  141. end;
  142. EIdCannotUseNonSocketIOHandler = class(EIdException);
  143. implementation
  144. uses
  145. IdExceptionCore,
  146. IdIOHandlerStack,
  147. IdIOHandlerSocket,
  148. IdCustomTransparentProxy,
  149. IdResourceStringsCore,
  150. IdStack;
  151. { TIdSimpleServer }
  152. procedure TIdSimpleServer.Abort;
  153. begin
  154. FAbortedRequested := True;
  155. end;
  156. procedure TIdSimpleServer.BeginListen;
  157. var
  158. // under ARC, convert a weak reference to a strong reference before working with it
  159. LProxy: TIdCustomTransparentProxy;
  160. begin
  161. // Must be before IOHandler as it resets it
  162. EndListen;
  163. CreateBinding;
  164. LProxy := Socket.TransparentProxy;
  165. if LProxy.Enabled then begin
  166. Socket.Binding.IP := BoundIP;
  167. LProxy.Bind(FIOHandler, BoundPort);
  168. end else begin
  169. Bind;
  170. Binding.Listen(1);
  171. end;
  172. FListening := True;
  173. end;
  174. procedure TIdSimpleServer.Bind;
  175. var
  176. LBinding: TIdSocketHandle;
  177. begin
  178. LBinding := Binding;
  179. try
  180. DoBeforeBind;
  181. LBinding.IPVersion := FIPVersion; // needs to be before AllocateSocket, because AllocateSocket uses this
  182. LBinding.AllocateSocket;
  183. FListenHandle := LBinding.Handle;
  184. LBinding.IP := BoundIP;
  185. LBinding.Port := BoundPort;
  186. LBinding.ClientPortMin := BoundPortMin;
  187. LBinding.ClientPortMax := BoundPortMax;
  188. LBinding.Bind;
  189. DoAfterBind;
  190. except
  191. FListenHandle := Id_INVALID_SOCKET;
  192. raise;
  193. end;
  194. end;
  195. procedure TIdSimpleServer.CreateBinding;
  196. begin
  197. if not Assigned(IOHandler) then begin
  198. CreateIOHandler();
  199. end;
  200. IOHandler.Open;
  201. end;
  202. procedure TIdSimpleServer.DoBeforeBind;
  203. begin
  204. if Assigned(FOnBeforeBind) then begin
  205. FOnBeforeBind(self);
  206. end;
  207. end;
  208. procedure TIdSimpleServer.DoAfterBind;
  209. begin
  210. if Assigned(FOnAfterBind) then begin
  211. FOnAfterBind(self);
  212. end;
  213. end;
  214. procedure TIdSimpleServer.EndListen;
  215. begin
  216. FAbortedRequested := False;
  217. FListening := False;
  218. end;
  219. function TIdSimpleServer.GetBinding: TIdSocketHandle;
  220. begin
  221. if Assigned(Socket) then begin
  222. Result := Socket.Binding;
  223. end else begin
  224. Result := nil;
  225. end;
  226. end;
  227. procedure TIdSimpleServer.SetIOHandler(AValue: TIdIOHandler);
  228. begin
  229. if Assigned(AValue) then begin
  230. if not (AValue is TIdIOHandlerSocket) then begin
  231. raise EIdCannotUseNonSocketIOHandler.Create(RSCannotUseNonSocketIOHandler);
  232. end;
  233. end;
  234. inherited SetIOHandler(AValue);
  235. end;
  236. procedure TIdSimpleServer.SetIPVersion(const AValue: TIdIPVersion);
  237. begin
  238. FIPVersion := AValue;
  239. if Assigned(Socket) then begin
  240. Socket.IPVersion := AValue;
  241. end;
  242. end;
  243. procedure TIdSimpleServer.Listen(ATimeout: Integer = IdTimeoutDefault);
  244. var
  245. // under ARC, convert a weak reference to a strong reference before working with it
  246. LProxy: TIdCustomTransparentProxy;
  247. LAccepted: Boolean;
  248. function DoListenTimeout(ALTimeout: Integer; AUseProxy: Boolean): Boolean;
  249. var
  250. LSleepTime: Integer;
  251. begin
  252. LSleepTime := AcceptWait;
  253. if ALTimeout = IdTimeoutDefault then begin
  254. ALTimeout := IdTimeoutInfinite;
  255. end;
  256. if ALTimeout = IdTimeoutInfinite then begin
  257. repeat
  258. if AUseProxy then begin
  259. Result := LProxy.Listen(IOHandler, LSleepTime);
  260. end else begin
  261. Result := Binding.Select(LSleepTime);
  262. end;
  263. until Result or FAbortedRequested;
  264. Exit;
  265. end;
  266. while ALTimeout > LSleepTime do begin
  267. if AUseProxy then begin
  268. Result := LProxy.Listen(IOHandler, LSleepTime);
  269. end else begin
  270. Result := Binding.Select(LSleepTime);
  271. end;
  272. if Result or FAbortedRequested then begin
  273. Exit;
  274. end;
  275. Dec(ALTimeout, LSleepTime);
  276. end;
  277. if AUseProxy then begin
  278. Result := LProxy.Listen(IOHandler, ALTimeout);
  279. end else begin
  280. Result := Binding.Select(ALTimeout);
  281. end;
  282. end;
  283. begin
  284. if not FListening then begin
  285. BeginListen;
  286. end;
  287. LProxy := Socket.TransparentProxy;
  288. if LProxy.Enabled then begin
  289. LAccepted := DoListenTimeout(ATimeout, True);
  290. end else
  291. begin
  292. LAccepted := DoListenTimeout(ATimeout, False);
  293. if LAccepted then begin
  294. if Binding.Accept(Binding.Handle) then begin
  295. IOHandler.AfterAccept;
  296. end;
  297. end;
  298. // This is now protected. Disconnect replaces it - but it also calls shutdown.
  299. // Im not sure we want to call shutdown here? Need to investigate before fixing
  300. // this.
  301. GStack.Disconnect(FListenHandle);
  302. FListenHandle := Id_INVALID_SOCKET;
  303. end;
  304. if not LAccepted then begin
  305. raise EIdAcceptTimeout.Create(RSAcceptTimeout);
  306. end;
  307. end;
  308. procedure TIdSimpleServer.InitComponent;
  309. begin
  310. inherited InitComponent;
  311. FIPVersion := ID_DEFAULT_IP_VERSION;
  312. FAcceptWait := ID_ACCEPT_WAIT;
  313. FListenHandle := Id_INVALID_SOCKET;
  314. end;
  315. end.