<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ --> <title>src/Network/Socket/SendFile/Iter.hs</title> <link type='text/css' rel='stylesheet' href='hscolour.css' /> </head> <body> <pre><a name="line-1"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Network</span><span class='hs-varop'>.</span><span class='hs-conid'>Socket</span><span class='hs-varop'>.</span><span class='hs-conid'>SendFile</span><span class='hs-varop'>.</span><span class='hs-conid'>Iter</span> <span class='hs-keyword'>where</span> <a name="line-2"></a> <a name="line-3"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Control</span><span class='hs-varop'>.</span><span class='hs-conid'>Concurrent</span> <span class='hs-layout'>(</span><span class='hs-varid'>threadWaitWrite</span><span class='hs-layout'>)</span> <a name="line-4"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Data</span><span class='hs-varop'>.</span><span class='hs-conid'>Int</span> <span class='hs-layout'>(</span><span class='hs-conid'>Int64</span><span class='hs-layout'>)</span> <a name="line-5"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>System</span><span class='hs-varop'>.</span><span class='hs-conid'>Posix</span><span class='hs-varop'>.</span><span class='hs-conid'>Types</span> <span class='hs-layout'>(</span><span class='hs-conid'>Fd</span><span class='hs-layout'>)</span> <a name="line-6"></a> <a name="line-7"></a><a name="Iter"></a><span class='hs-comment'>-- | An iteratee for sendfile</span> <a name="line-8"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-9"></a><a name="Iter"></a><span class='hs-comment'>-- In general, a whole file is not sent by a single call to</span> <a name="line-10"></a><a name="Iter"></a><span class='hs-comment'>-- sendfile(), but a series of calls which send successive pieces.</span> <a name="line-11"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-12"></a><a name="Iter"></a><span class='hs-comment'>-- The high-level API in this sendfile library has calls which will</span> <a name="line-13"></a><a name="Iter"></a><span class='hs-comment'>-- send the entire file (or an entire requested offset+length), before</span> <a name="line-14"></a><a name="Iter"></a><span class='hs-comment'>-- returning.</span> <a name="line-15"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-16"></a><a name="Iter"></a><span class='hs-comment'>-- However, there are instances where you want to be a bit more</span> <a name="line-17"></a><a name="Iter"></a><span class='hs-comment'>-- involved in the sending loop. For example, if you want to tickle a</span> <a name="line-18"></a><a name="Iter"></a><span class='hs-comment'>-- timeout after each chunk is sent or update a progress bar.</span> <a name="line-19"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-20"></a><a name="Iter"></a><span class='hs-comment'>-- The 'Iter' type gives you that power with out requiring you to</span> <a name="line-21"></a><a name="Iter"></a><span class='hs-comment'>-- manage all the low-level details of the sendfile loop. The</span> <a name="line-22"></a><a name="Iter"></a><span class='hs-comment'>-- interface is simple and consistant across all platforms.</span> <a name="line-23"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-24"></a><a name="Iter"></a><span class='hs-comment'>-- A call to sendfile() can result in three different states:</span> <a name="line-25"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-26"></a><a name="Iter"></a><span class='hs-comment'>-- (1) the requested number of bytes for that iteration was sent</span> <a name="line-27"></a><a name="Iter"></a><span class='hs-comment'>-- successfully, there are more bytes left to send.</span> <a name="line-28"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-29"></a><a name="Iter"></a><span class='hs-comment'>-- (2) some (possibly 0) bytes were sent, but the file descriptor</span> <a name="line-30"></a><a name="Iter"></a><span class='hs-comment'>-- would now block if more bytes were written. There are more bytes</span> <a name="line-31"></a><a name="Iter"></a><span class='hs-comment'>-- left to send.</span> <a name="line-32"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-33"></a><a name="Iter"></a><span class='hs-comment'>-- (2) All the bytes were sent, and there is nothing left to send.</span> <a name="line-34"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-35"></a><a name="Iter"></a><span class='hs-comment'>-- We handle these three cases by using a type with three</span> <a name="line-36"></a><a name="Iter"></a><span class='hs-comment'>-- constructors:</span> <a name="line-37"></a><a name="Iter"></a><span class='hs-comment'>-- </span> <a name="line-38"></a><a name="Iter"></a><span class='hs-comment'>-- @</span> <a name="line-39"></a><a name="Iter"></a><span class='hs-comment'>-- data Iter</span> <a name="line-40"></a><a name="Iter"></a><span class='hs-comment'>-- = Sent Int64 (IO Iter)</span> <a name="line-41"></a><a name="Iter"></a><span class='hs-comment'>-- | WouldBlock Int64 Fd (IO Iter)</span> <a name="line-42"></a><a name="Iter"></a><span class='hs-comment'>-- | Done Int64 </span> <a name="line-43"></a><a name="Iter"></a><span class='hs-comment'>-- @</span> <a name="line-44"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-45"></a><a name="Iter"></a><span class='hs-comment'>-- All three constructors provide an 'Int64' which represents the</span> <a name="line-46"></a><a name="Iter"></a><span class='hs-comment'>-- number of bytes sent for that particular iteration. (Not the total</span> <a name="line-47"></a><a name="Iter"></a><span class='hs-comment'>-- byte count).</span> <a name="line-48"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-49"></a><a name="Iter"></a><span class='hs-comment'>-- The 'Sent' and 'WouldBlock' constructors provide 'IO' 'Iter' as their</span> <a name="line-50"></a><a name="Iter"></a><span class='hs-comment'>-- final argument. Running this IO action will send the next block of</span> <a name="line-51"></a><a name="Iter"></a><span class='hs-comment'>-- data.</span> <a name="line-52"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-53"></a><a name="Iter"></a><span class='hs-comment'>-- The 'WouldBlock' constructor also provides the 'Fd' for the output</span> <a name="line-54"></a><a name="Iter"></a><span class='hs-comment'>-- socket. You should not send anymore data until the 'Fd' would not</span> <a name="line-55"></a><a name="Iter"></a><span class='hs-comment'>-- block. The easiest way to do that is to use 'threadWaitWrite' to</span> <a name="line-56"></a><a name="Iter"></a><span class='hs-comment'>-- suspend the thread until the 'Fd' is available.</span> <a name="line-57"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-58"></a><a name="Iter"></a><span class='hs-comment'>-- A very simple function to drive the Iter might look like:</span> <a name="line-59"></a><a name="Iter"></a><span class='hs-comment'>-- </span> <a name="line-60"></a><a name="Iter"></a><span class='hs-comment'>-- @</span> <a name="line-61"></a><a name="Iter"></a><span class='hs-comment'>-- runIter :: IO Iter -> IO ()</span> <a name="line-62"></a><a name="Iter"></a><span class='hs-comment'>-- runIter iter =</span> <a name="line-63"></a><a name="Iter"></a><span class='hs-comment'>-- do r <- iter</span> <a name="line-64"></a><a name="Iter"></a><span class='hs-comment'>-- case r of</span> <a name="line-65"></a><a name="Iter"></a><span class='hs-comment'>-- (Done _n) -> return ()</span> <a name="line-66"></a><a name="Iter"></a><span class='hs-comment'>-- (Sent _n cont) -> runIter cont</span> <a name="line-67"></a><a name="Iter"></a><span class='hs-comment'>-- (WouldBlock _n fd cont) -> </span> <a name="line-68"></a><a name="Iter"></a><span class='hs-comment'>-- do threadWaitWrite fd</span> <a name="line-69"></a><a name="Iter"></a><span class='hs-comment'>-- runIter cont</span> <a name="line-70"></a><a name="Iter"></a><span class='hs-comment'>-- @</span> <a name="line-71"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-72"></a><a name="Iter"></a><span class='hs-comment'>-- You would use it as the first argument to a *IterWith function, e.g.</span> <a name="line-73"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-74"></a><a name="Iter"></a><span class='hs-comment'>-- @</span> <a name="line-75"></a><a name="Iter"></a><span class='hs-comment'>-- sendFileIterWith runIter outputSocket \"\/path\/to\/file\" 2^16 </span> <a name="line-76"></a><a name="Iter"></a><span class='hs-comment'>-- @</span> <a name="line-77"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-78"></a><a name="Iter"></a><span class='hs-comment'>-- The 'runIter' function provided by this module is similar, but also returns the total number of bytes sent.</span> <a name="line-79"></a><a name="Iter"></a><span class='hs-comment'>--</span> <a name="line-80"></a><a name="Iter"></a><span class='hs-comment'>-- NOTE: You must not use the 'Fd' or the 'IO' 'Iter' after the call</span> <a name="line-81"></a><a name="Iter"></a><span class='hs-comment'>-- to *IterWith has returned. When the *IterWith functions return,</span> <a name="line-82"></a><a name="Iter"></a><span class='hs-comment'>-- the file descriptors may be closed due to finalizers running.</span> <a name="line-83"></a><a name="Iter"></a><span class='hs-keyword'>data</span> <span class='hs-conid'>Iter</span> <a name="line-84"></a> <span class='hs-keyglyph'>=</span> <span class='hs-conid'>Sent</span> <span class='hs-conid'>Int64</span> <span class='hs-layout'>(</span><span class='hs-conid'>IO</span> <span class='hs-conid'>Iter</span><span class='hs-layout'>)</span> <span class='hs-comment'>-- ^ number of bytes sent this pass and a continuation to send more</span> <a name="line-85"></a> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>WouldBlock</span> <span class='hs-conid'>Int64</span> <span class='hs-conid'>Fd</span> <span class='hs-layout'>(</span><span class='hs-conid'>IO</span> <span class='hs-conid'>Iter</span><span class='hs-layout'>)</span> <span class='hs-comment'>-- ^ number of bytes sent, Fd that blocked, continuation to send more. NOTE: The Fd should not be used outside the running of the Iter as it may be freed when the Iter is done</span> <a name="line-86"></a> <span class='hs-keyglyph'>|</span> <span class='hs-conid'>Done</span> <span class='hs-conid'>Int64</span> <span class='hs-comment'>-- ^ number of bytes sent, no more to send</span> <a name="line-87"></a> <a name="line-88"></a><a name="runIter"></a><span class='hs-comment'>-- | A simple function to drive the *IterWith functions.</span> <a name="line-89"></a><span class='hs-comment'>-- It returns the total number of bytes sent.</span> <a name="line-90"></a><span class='hs-definition'>runIter</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>IO</span> <span class='hs-conid'>Iter</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>IO</span> <span class='hs-conid'>Int64</span> <a name="line-91"></a><span class='hs-definition'>runIter</span> <span class='hs-keyglyph'>=</span> <span class='hs-varid'>runIter'</span> <span class='hs-num'>0</span> <a name="line-92"></a> <span class='hs-keyword'>where</span> <a name="line-93"></a> <span class='hs-varid'>runIter'</span> <span class='hs-keyglyph'>::</span> <span class='hs-conid'>Int64</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>IO</span> <span class='hs-conid'>Iter</span> <span class='hs-keyglyph'>-></span> <span class='hs-conid'>IO</span> <span class='hs-conid'>Int64</span> <a name="line-94"></a> <span class='hs-varid'>runIter'</span> <span class='hs-varid'>acc</span> <span class='hs-varid'>iter</span> <span class='hs-keyglyph'>=</span> <a name="line-95"></a> <span class='hs-keyword'>do</span> <span class='hs-varid'>r</span> <span class='hs-keyglyph'><-</span> <span class='hs-varid'>iter</span> <a name="line-96"></a> <span class='hs-keyword'>case</span> <span class='hs-varid'>r</span> <span class='hs-keyword'>of</span> <a name="line-97"></a> <span class='hs-layout'>(</span><span class='hs-conid'>Sent</span> <span class='hs-varid'>n</span> <span class='hs-varid'>cont</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <a name="line-98"></a> <span class='hs-keyword'>do</span> <span class='hs-keyword'>let</span> <span class='hs-varid'>acc'</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>acc</span> <span class='hs-varop'>+</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <a name="line-99"></a><span class='hs-comment'>-- putStrLn $ "Sent " ++ show acc'</span> <a name="line-100"></a> <span class='hs-varid'>acc'</span> <span class='hs-varop'>`seq`</span> <span class='hs-varid'>runIter'</span> <span class='hs-varid'>acc'</span> <span class='hs-varid'>cont</span> <a name="line-101"></a> <span class='hs-layout'>(</span><span class='hs-conid'>Done</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <a name="line-102"></a> <span class='hs-keyword'>do</span> <span class='hs-comment'>-- putStrLn $ "Done " ++ show (acc + n)</span> <a name="line-103"></a> <span class='hs-varid'>return</span> <span class='hs-layout'>(</span><span class='hs-varid'>acc</span> <span class='hs-varop'>+</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <a name="line-104"></a> <span class='hs-layout'>(</span><span class='hs-conid'>WouldBlock</span> <span class='hs-varid'>n</span> <span class='hs-varid'>fd</span> <span class='hs-varid'>cont</span><span class='hs-layout'>)</span> <span class='hs-keyglyph'>-></span> <a name="line-105"></a> <span class='hs-keyword'>do</span> <span class='hs-varid'>threadWaitWrite</span> <span class='hs-varid'>fd</span> <a name="line-106"></a> <span class='hs-keyword'>let</span> <span class='hs-varid'>acc'</span> <span class='hs-keyglyph'>=</span> <span class='hs-layout'>(</span><span class='hs-varid'>acc</span> <span class='hs-varop'>+</span> <span class='hs-varid'>n</span><span class='hs-layout'>)</span> <a name="line-107"></a><span class='hs-comment'>-- putStrLn $ "WouldBlock " ++ (show acc')</span> <a name="line-108"></a> <span class='hs-varid'>acc'</span> <span class='hs-varop'>`seq`</span> <span class='hs-varid'>runIter'</span> <span class='hs-varid'>acc'</span> <span class='hs-varid'>cont</span> </pre></body> </html>