Network.Socket.SendFile.Handle

sendfile-0.7.9: A portable sendfile library

Safe Haskell | None
Language | Haskell98

Network.Socket.SendFile.Handle

Contents

- Handle-based sendFiles

Description

Handle-based versions of some of the functions exported by Network.Socket.SendFile.

Synopsis

- type ByteCount = Integer
- type Offset = Integer
- data Iter
  - = Sent Int64 (IO Iter)
  - | WouldBlock Int64 Fd (IO Iter)
  - | Done Int64
- runIter :: IO Iter -> IO Int64
- sendFile :: Socket -> Handle -> IO ()
- sendFileIterWith :: (IO Iter -> IO a) -> Socket -> Handle -> ByteCount -> IO a
- sendFile' :: Socket -> Handle -> Offset -> ByteCount -> IO ()
- sendFileIterWith' :: (IO Iter -> IO a) -> Socket -> Handle -> ByteCount -> Offset -> ByteCount -> IO a

# Documentation

type ByteCount = Integer

The length (in bytes) which should be sent

type Offset = Integer

The file offset (in bytes) to start from

data Iter

An iteratee for sendfile

In general, a whole file is not sent by a single call to sendfile(), but a series of calls which send successive pieces.

The high-level API in this sendfile library has calls which will send the entire file (or an entire requested offset+length), before returning.

However, there are instances where you want to be a bit more involved in the sending loop. For example, if you want to tickle a timeout after each chunk is sent or update a progress bar.

The `Iter` type gives you that power with out requiring you to manage all the low-level details of the sendfile loop. The interface is simple and consistant across all platforms.

A call to sendfile() can result in three different states:

1. the requested number of bytes for that iteration was sent successfully, there are more bytes left to send.
2. some (possibly 0) bytes were sent, but the file descriptor would now block if more bytes were written. There are more bytes left to send.
3. All the bytes were sent, and there is nothing left to send.

We handle these three cases by using a type with three constructors:

     data Iter
         = Sent       Int64    (IO Iter)
         | WouldBlock Int64 Fd (IO Iter)
         | Done       Int64

All three constructors provide an `Int64` which represents the number of bytes sent for that particular iteration. (Not the total byte count).

The `Sent` and `WouldBlock` constructors provide `IO` `Iter` as their final argument. Running this IO action will send the next block of data.

The `WouldBlock` constructor also provides the `Fd` for the output socket. You should not send anymore data until the `Fd` would not block. The easiest way to do that is to use `threadWaitWrite` to suspend the thread until the `Fd` is available.

A very simple function to drive the Iter might look like:

    runIter :: IO Iter -> IO ()
    runIter iter =
       do r <- iter
          case r of
            (Done _n)      -> return ()
            (Sent _n cont) -> runIter cont
            (WouldBlock _n fd cont) ->
                do threadWaitWrite fd
                   runIter cont

You would use it as the first argument to a *IterWith function, e.g.

     sendFileIterWith runIter outputSocket "/path/to/file" 2^16

The `runIter` function provided by this module is similar, but also returns the total number of bytes sent.

NOTE: You must not use the `Fd` or the `IO` `Iter` after the call to *IterWith has returned. When the *IterWith functions return, the file descriptors may be closed due to finalizers running.

Constructors

Sent Int64 (IO Iter) | number of bytes sent this pass and a continuation to send more
WouldBlock Int64 Fd (IO Iter) | 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
Done Int64 | number of bytes sent, no more to send

runIter :: IO Iter -> IO Int64

A simple function to drive the *IterWith functions. It returns the total number of bytes sent.

# Handle-based sendFiles

sendFile :: Socket -> Handle -> IO ()

Simple sendFile - give it a Socket and a Handle, and it sends the entire file through the socket.

WARNING: This function will raise `IOError` `IllegalOperation` if the `Handle` is not for an `Fd`.

sendFileIterWith :: (IO Iter -> IO a) -> Socket -> Handle -> ByteCount -> IO a

A more interactive version of sendFile, which accepts a callback function in addition to the socket and handle. The callback will be called for each chunk of data the sendFileIterWith function acts on.

WARNING: This function will raise `IOError` `IllegalOperation` if the `Handle` is not for an `Fd`.

sendFile' :: Socket -> Handle -> Offset -> ByteCount -> IO ()

A sendFile that allows the user to send a subset of the file associated with the given handle.

WARNING: This function will raise `IOError` `IllegalOperation` if the `Handle` is not for an `Fd`.

sendFileIterWith' :: (IO Iter -> IO a) -> Socket -> Handle -> ByteCount -> Offset -> ByteCount -> IO a

A more powerful version of sendFileIterWith, which allows the sending of a subset of the given file.

WARNING: This function will raise `IOError` `IllegalOperation` if the `Handle` is not for an `Fd`.