sendfile-0.7.9: A portable sendfile library

Safe HaskellNone

Network.Socket.SendFile

Contents

Description

A cross-platform wrapper for sendfile -- this implements an available operating-system call if supported, otherwise it falls back to a portable haskell implementation.

Two interfaces are provided for both the unsafe and safe sets of functions. The first interface accepts an output socket/handle and the path of the file you want to send; sendFile and unsafeSendFile comprise this interface. The second interface accepts an output socket/handle, a handle to the file you want to send, an offset, and the number of bytes you want to send; sendFile' and unsafeSendFile' comprise this interface.

For consistent read/write behavior with either sendFile' or unsafeSendFile', the input handle should be opened in Binary mode rather than Text mode.

Synopsis

Documentation

type ByteCount = IntegerSource

The length (in bytes) which should be sent

type Offset = IntegerSource

The file offset (in bytes) to start from

data Iter Source

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 Int64Source

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

Safe functions (recommended)

sendFileSource

Arguments

:: Socket

The output socket

-> FilePath

The path where the input file resides

-> IO () 

The simplest interface. Simply give it an output Socket and the FilePath to the input file.

sendFileIterWithSource

Arguments

:: (IO Iter -> IO a) 
-> Socket

The output socket

-> FilePath

The path where the input file resides

-> ByteCount

Maximum bytes to send per block (may send less)

-> IO a 

The simplest interface. Simply give it an output Socket and the FilePath to the input file.

This variant takes a function to drive the iteration loop. See Iter for more information.

sendFile'Source

Arguments

:: Socket

The output socket

-> FilePath

The input file path

-> Offset

The offset to start at

-> ByteCount

The number of bytes to send

-> IO () 

A more powerful interface than sendFile which accepts a starting offset, and the bytecount to send; the offset and the count must be a positive integer. The initial position of the input file handle matters not since the offset is absolute, and the final position may be different depending on the platform -- no assumptions can be made.

sendFileIterWith'Source

Arguments

:: (IO Iter -> IO a) 
-> Socket

The output socket

-> FilePath

The input file path

-> ByteCount

Maximum bytes to send per block (may send less)

-> Offset

The offset to start at

-> ByteCount

The number of bytes to send

-> IO a 

A more powerful interface than sendFile which accepts a starting offset, and the bytecount to send; the offset and the count must be a positive integer. The initial position of the input file handle matters not since the offset is absolute, and the final position may be different depending on the platform -- no assumptions can be made.

This variant takes a function to drive the iteration loop. See Iter for more information.

Unsafe functions

These functions are unsafe simply because there is no guarantee that the Handle used for output is actually bound to a Socket. If it is not, it will result in a runtime error.

unsafeSendFileSource

Arguments

:: Handle

The output handle

-> FilePath

The path where the input file resides

-> IO () 

The unsafe version of sendFile which accepts a Handle instead of a Socket for the output. It will flush the output handle before sending any file data.

unsafeSendFileIterWithSource

Arguments

:: (IO Iter -> IO a) 
-> Handle

The output handle

-> FilePath

The path where the input file resides

-> ByteCount

Maximum bytes to send per block (may send less)

-> IO a 

The unsafe version of sendFile which accepts a Handle instead of a Socket for the output. It will flush the output handle before sending any file data.

This variant takes a function to drive the iteration loop. See Iter for more information.

unsafeSendFile'Source

Arguments

:: Handle

The output handle

-> FilePath

The input filepath

-> Offset

The offset to start at

-> ByteCount

The number of bytes to send

-> IO () 

The unsafe version of sendFile' which accepts a Handle instead of a Socket for the output. It will flush the output handle before sending any file data.

unsafeSendFileIterWith'Source

Arguments

:: (IO Iter -> IO a) 
-> Handle

The output handle

-> FilePath

The input filepath

-> ByteCount

The number of bytes to send

-> Offset

The offset to start at

-> ByteCount

The number of bytes to send

-> IO a 

The unsafe version of sendFile' which accepts a Handle instead of a Socket for the output. It will flush the output handle before sending any file data.

This variant takes a function to drive the iteration loop. See Iter for more information.

Utility functions

sendFileModeSource

Arguments

:: String

The mode that sendfile was compiled with

Returns the mode that sendfile was compiled with. Mainly for debugging use. Possible values are WIN32_SENDFILE, LINUX_SENDFILE, FREEBSD_SENDFILE, DARWIN_SENDFILE, and PORTABLE_SENDFILE.