IdWorkOpUnits.pas 10 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.4 6/11/2004 8:40:12 AM DSiders
  18. Added "Do not Localize" comments.
  19. Rev 1.3 2004.05.06 1:47:28 PM czhower
  20. Now uses IndexOf
  21. Rev 1.2 2004.04.22 11:45:18 PM czhower
  22. Bug fixes
  23. Rev 1.1 2004.02.09 9:16:58 PM czhower
  24. Updated to compile and match lib changes.
  25. Rev 1.0 2004.02.03 12:39:10 AM czhower
  26. Move
  27. Rev 1.14 2003.10.19 2:50:42 PM czhower
  28. Fiber cleanup
  29. Rev 1.13 2003.10.11 5:44:20 PM czhower
  30. Chained servers now functional.
  31. Rev 1.12 2003.07.17 4:42:08 PM czhower
  32. More IOCP improvements.
  33. Rev 1.11 2003.07.17 3:55:18 PM czhower
  34. Removed IdIOChainEngineIOCP and merged it into TIdChaingEngine in
  35. IdIOHandlerChain.pas.
  36. Rev 1.7 2003.07.14 11:00:52 PM czhower
  37. More IOCP fixes.
  38. Rev 1.6 2003.07.14 12:54:34 AM czhower
  39. Fixed graceful close detection if it occurs after connect.
  40. Rev 1.5 7/7/2003 1:25:26 PM BGooijen
  41. Added BytesSent property to TIdWorkOpUnitWriteFile
  42. Rev 1.4 7/5/2003 11:47:14 PM BGooijen
  43. Added TIdWorkOpUnitCheckForDisconnect and TIdWorkOpUnitWriteFile
  44. Rev 1.3 3/27/2003 2:43:06 PM BGooijen
  45. Added woWriteStream and woWriteBuffer
  46. Rev 1.2 3/22/2003 09:45:30 PM JPMugaas
  47. Now should compile under D4.
  48. Rev 1.1 3/2/2003 12:36:26 AM BGooijen
  49. Added woReadBuffer and TIdWorkOpUnitReadBuffer to read a buffer. Now
  50. ReadBuffer doesn't use ReadStream any more.
  51. TIdIOHandlerChain.ReadLn now supports MaxLineLength (splitting, and
  52. exceptions).
  53. woReadLn doesn't check the intire buffer any more, but continued where it
  54. stopped the last time.
  55. Added basic support for timeouts (probably only on read operations, and maybe
  56. connect), accuratie of timeout is currently 500msec.
  57. Rev 1.0 2/27/2003 10:11:50 PM BGooijen
  58. WorkOpUnits combined in one file
  59. }
  60. unit IdWorkOpUnits;
  61. interface
  62. uses
  63. Classes,
  64. IdWorkOpUnit, IdGlobal,
  65. SysUtils;
  66. type
  67. TIdWorkOpUnitStreamBaseRead = class(TIdWorkOpUnitRead)
  68. protected
  69. FStream: TStream;
  70. public
  71. constructor Create(AStream: TStream); reintroduce; virtual;
  72. end;
  73. TIdWorkOpUnitStreamBaseWrite = class(TIdWorkOpUnitWrite)
  74. protected
  75. FFreeStream: Boolean;
  76. FStream: TStream;
  77. public
  78. constructor Create(
  79. AStream: TStream;
  80. AFreeStream: Boolean = True
  81. ); reintroduce; virtual;
  82. destructor Destroy; override;
  83. end;
  84. TIdWorkOpUnitWriteBuffer = class(TIdWorkOpUnitWrite)
  85. protected
  86. FBuffer: Pointer;
  87. FFreeBuffer: Boolean;
  88. FSize: Integer;
  89. //
  90. procedure Processing(ABytes: Integer); override;
  91. procedure Starting; override;
  92. public
  93. constructor Create(ABuffer: Pointer; ASize: Integer;
  94. AFreeBuffer: Boolean = True); reintroduce; virtual;
  95. destructor Destroy; override;
  96. end;
  97. TIdWorkOpUnitWriteFile = class(TIdWorkOpUnitWrite)
  98. protected
  99. FFilename: String;
  100. FBytesSent: Integer;
  101. //
  102. procedure Processing(ABytes: Integer); override;
  103. procedure Starting; override;
  104. public
  105. constructor Create(AFileName: string); reintroduce;
  106. end;
  107. TIdWorkOpUnitWriteStream = class(TIdWorkOpUnitStreamBaseWrite)
  108. protected
  109. FCount: Integer;
  110. FStartPos: Integer;
  111. //
  112. procedure Processing(ABytes: Integer); override;
  113. procedure Starting; override;
  114. public
  115. constructor Create(AStream: TStream; AStartPos, ACount: Integer;
  116. AFreeStream: Boolean); reintroduce; virtual;
  117. end;
  118. TIdWorkOpUnitWaitConnected = class(TIdWorkOpUnit)
  119. protected
  120. procedure Starting; override;
  121. public
  122. procedure Process(
  123. AOverlapped: PIdOverlapped;
  124. AByteCount: Integer
  125. ); override;
  126. end;
  127. TIdWorkOpUnitReadSized = class(TIdWorkOpUnitRead)
  128. protected
  129. FSize: Integer;
  130. //
  131. procedure Processing(
  132. ABuffer: TIdBytes
  133. ); override;
  134. public
  135. constructor Create(ASize: Integer); reintroduce;
  136. end;
  137. TIdWorkOpUnitReadSizedStream = class(TIdWorkOpUnitStreamBaseRead)
  138. protected
  139. FSize: Integer;
  140. //
  141. procedure Processing(
  142. ABuffer: TIdBytes
  143. ); override;
  144. public
  145. constructor Create(AStream: TStream; ASize: Integer);
  146. reintroduce;
  147. end;
  148. TIdWorkOpUnitReadLn = class(TIdWorkOpUnitRead)
  149. protected
  150. FLastPos: Integer;
  151. FMaxLength: Integer;
  152. FTerminator: string;
  153. //
  154. procedure Processing(
  155. ABuffer: TIdBytes
  156. ); override;
  157. public
  158. constructor Create(
  159. ATerminator: string;
  160. AMaxLength: Integer
  161. ); reintroduce;
  162. end;
  163. TIdWorkOpUnitReadUntilDisconnect = class(TIdWorkOpUnitStreamBaseRead)
  164. protected
  165. procedure Processing(
  166. ABuffer: TIdBytes
  167. ); override;
  168. end;
  169. TIdWorkOpUnitReadAvailable = class(TIdWorkOpUnitRead)
  170. protected
  171. procedure Processing(
  172. ABuffer: TIdBytes
  173. ); override;
  174. end;
  175. implementation
  176. { TIdWorkOpUnitWriteStream }
  177. constructor TIdWorkOpUnitWriteStream.Create(AStream: TStream; AStartPos,ACount:integer; AFreeStream: Boolean);
  178. begin
  179. inherited Create(AStream, AFreeStream);
  180. FStream.Position := AStartPos;
  181. FCount := ACount;
  182. end;
  183. procedure TIdWorkOpUnitWriteStream.Processing(ABytes: Integer);
  184. //TODO: This used to use pages from IdBuffer, which because of .Net do not exist
  185. // anymore. We need to maybe keep a local persistent buffer instead then for
  186. // storage reasons.
  187. var
  188. LBuffer: TIdBytes;
  189. LSize: Integer;
  190. begin
  191. FCount := FCount - ABytes;
  192. if FCount = 0 then begin
  193. Complete;
  194. end else begin
  195. FStream.Position := ABytes;
  196. //
  197. //TODO: Dont hard code this value. Also find an optimal size for IOCP
  198. LSize := Min(FCount, WOPageSize);
  199. SetLength(LBuffer, LSize);
  200. //
  201. FStream.ReadBuffer(LBuffer[0], LSize);
  202. Write(@LBuffer[0], LSize);
  203. end;
  204. end;
  205. procedure TIdWorkOpUnitWriteStream.Starting;
  206. begin
  207. Processing(0);
  208. end;
  209. { TIdWorkOpUnitWriteBuffer }
  210. constructor TIdWorkOpUnitWriteBuffer.Create(ABuffer: pointer; ASize: integer; AFreeBuffer: Boolean = True);
  211. begin
  212. inherited Create;
  213. FSize := ASize;
  214. FBuffer := ABuffer;
  215. FFreeBuffer := AFreeBuffer;
  216. end;
  217. destructor TIdWorkOpUnitWriteBuffer.Destroy;
  218. begin
  219. if FFreeBuffer then begin
  220. FreeMem(FBuffer);
  221. FBuffer := nil;
  222. end;
  223. inherited;
  224. end;
  225. procedure TIdWorkOpUnitWriteBuffer.Processing(ABytes: Integer);
  226. begin
  227. //TODO: Change the pointer to a type that points to bytes
  228. FBuffer := Pointer(Cardinal(FBuffer) + Cardinal(ABytes));
  229. FSize := FSize - ABytes;
  230. if FSize = 0 then begin
  231. Complete;
  232. end else begin
  233. //TODO: Reduce this down so it never sends more than a page
  234. Write(FBuffer, Min(FSize, WOPageSize));
  235. end;
  236. end;
  237. procedure TIdWorkOpUnitWriteBuffer.Starting;
  238. begin
  239. Processing(0);
  240. end;
  241. { TIdWorkOpUnitWriteFile }
  242. constructor TIdWorkOpUnitWriteFile.Create(AFileName:string);
  243. begin
  244. inherited Create;
  245. FFilename := AFileName;
  246. end;
  247. procedure TIdWorkOpUnitWriteFile.Processing(ABytes: Integer);
  248. begin
  249. Assert(False, 'Need to implement WriteFile, also add to a bubble'); {do not localize}
  250. end;
  251. procedure TIdWorkOpUnitWriteFile.Starting;
  252. begin
  253. end;
  254. { TIdWorkOpUnitSizedStream }
  255. constructor TIdWorkOpUnitReadSizedStream.Create(AStream: TStream; ASize:integer);
  256. begin
  257. inherited Create(AStream);
  258. FSize := ASize;
  259. end;
  260. procedure TIdWorkOpUnitWaitConnected.Process(
  261. AOverlapped: PIdOverlapped;
  262. AByteCount: Integer
  263. );
  264. begin
  265. end;
  266. procedure TIdWorkOpUnitWaitConnected.Starting;
  267. begin
  268. end;
  269. { TIdWorkOpUnitReadLn }
  270. constructor TIdWorkOpUnitReadLn.Create(
  271. ATerminator: string;
  272. AMaxLength: Integer);
  273. begin
  274. inherited Create;
  275. FLastPos := 1;
  276. FTerminator := ATerminator;
  277. FMaxLength := AMaxLength;
  278. end;
  279. procedure TIdWorkOpUnitReadLn.Processing(
  280. ABuffer: TIdBytes
  281. );
  282. begin
  283. //TODO: ReadLn is very common. Need to optimize this class and maybe
  284. // even pass pack the result directly so we dont search twice.
  285. //Also allow for hinting from the user.
  286. IOHandler.InputBuffer.Write(ABuffer);
  287. if not IOHandler.Connected then begin
  288. Complete;
  289. end else if IOHandler.InputBuffer.IndexOf(FTerminator, FLastPos) = -1 then begin
  290. Read;
  291. end else begin
  292. Complete;
  293. end;
  294. end;
  295. procedure TIdWorkOpUnitReadUntilDisconnect.Processing(
  296. ABuffer: TIdBytes
  297. );
  298. begin
  299. // 0 is disconnected, so keep requesting til 0
  300. if Length(ABuffer) = 0 then begin
  301. Complete;
  302. end else begin
  303. FStream.WriteBuffer(ABuffer[0], Length(ABuffer));
  304. Read;
  305. end;
  306. end;
  307. { TIdWorkOpUnitReadAvailable }
  308. procedure TIdWorkOpUnitReadAvailable.Processing(
  309. ABuffer: TIdBytes
  310. );
  311. begin
  312. Complete;
  313. end;
  314. { TIdWorkOpUnitReadSized }
  315. constructor TIdWorkOpUnitReadSized.Create(ASize: Integer);
  316. begin
  317. inherited Create;
  318. FSize := ASize;
  319. end;
  320. procedure TIdWorkOpUnitReadSized.Processing(
  321. ABuffer: TIdBytes
  322. );
  323. begin
  324. IOHandler.InputBuffer.Write(ABuffer);
  325. FSize := FSize - Length(ABuffer);
  326. if FSize = 0 then begin
  327. Complete;
  328. end else begin
  329. Read;
  330. end;
  331. end;
  332. { TIdWorkOpUnitStreamBaseRead }
  333. constructor TIdWorkOpUnitStreamBaseRead.Create(AStream: TStream);
  334. begin
  335. inherited Create;
  336. FStream := AStream;
  337. end;
  338. { TIdWorkOpUnitStreamBaseWrite }
  339. constructor TIdWorkOpUnitStreamBaseWrite.Create(AStream: TStream;
  340. AFreeStream: Boolean);
  341. begin
  342. inherited Create;
  343. FStream := AStream;
  344. FFreeStream := AFreeStream;
  345. end;
  346. destructor TIdWorkOpUnitStreamBaseWrite.Destroy;
  347. begin
  348. if FFreeStream then begin
  349. FreeAndNil(FStream);
  350. end;
  351. inherited;
  352. end;
  353. procedure TIdWorkOpUnitReadSizedStream.Processing(
  354. ABuffer: TIdBytes
  355. );
  356. begin
  357. FStream.WriteBuffer(ABuffer[0], Length(ABuffer));
  358. FSize := FSize - Length(ABuffer);
  359. if FSize = 0 then begin
  360. Complete;
  361. end else begin
  362. Read;
  363. end;
  364. end;
  365. end.