(* $Id$ *)
(** Senders and receivers for the FTP data connection *)
(* *********************************************************************)
(** {1 Types and Exceptions} *)
type ftp_data_prot =
[ `C | `S | `E | `P ]
(** See {!Netftp_client.ftp_data_prot} *)
type ftp_protector =
{ ftp_wrap_limit : unit -> int;
ftp_wrap_s : string -> string;
ftp_wrap_m : Netsys_types.memory -> Netsys_types.memory -> int;
ftp_unwrap_s : string -> string;
ftp_unwrap_m : Netsys_types.memory -> Netsys_types.memory -> int;
ftp_prot_level : ftp_data_prot;
ftp_close : unit -> unit;
mutable ftp_gssapi_props : Netsys_gssapi.client_props option;
mutable ftp_auth_loop : bool;
}
(** The functions for encrypting (wrapping) and decrypting (unwrapping)
messages when an RFC 2228 security layer is active.
*)
(** An [out_record_channel] can be used to output files with record
* structure. This is purely abstract, as Unix does not support such
* files natively, so this kind of channel is usually mapped to a flat
* representation when stored in a real file, e.g. record boundaries
* become newline characters.
*)
class type out_record_channel =
object
inherit Netchannels.out_obj_channel
method output_eor : unit -> unit
(** Finishes the current record.
*
* The record model is as follows: At the beginning of the channel,
* or after [output_eor], a new record can be potentially started.
* However, the record counts only as existing when either at least
* one byte is output, or the record is explicitly ended with a
* [output_eor] call.
*
* This rule allows it to represent channels containing no records.
* There is an ambiguity at the end of the channel, however: It is
* possible that there are characters between the last EOR and the
* EOF. This could also be represented by printing another EOR just
* before EOF. The preferred representation is the latter.
*
* This model correlates to the usual rules for line-structured
* files, so think EOR = EOL.
*)
end
(** An [in_record_channel] can be used to read files with record
* structure. This is purely abstract, as Unix does not support such
* files natively, so this kind of channel is usually mapped to a flat
* representation when stored in a real file, e.g. record boundaries
* become newline characters.
*)
class type in_record_channel =
object
inherit Netchannels.in_obj_channel
method input_eor : unit -> unit
(** Skips over the remaining data of the current record and the
* record boundary to the next record. Raises [End_of_file] when
* the current record is the "EOF" record (see below for explanations).
*
* A record channel can be read as follows: After opening the channel,
* one can read the contents of the first record with the [input]
* method. The end of the record is indicated by an [End_of_file]
* exception. By calling [input_eor], the next record is opened
* and can be read.
*
* After the last real record, there is always a special
* "EOF" record which is empty, and must be ignored by applications
* processing records. This means, after opening an empty channel,
* the current record is this "EOF" record, and [input_eor] raises
* [End_of_file]. After reading a non-empty channel, one can
* do [input_eor] after the last regular record, and the following
* [input_eor] raises [End_of_file].
*)
end
type local_receiver =
[ `File_structure of Netchannels.out_obj_channel
| `Record_structure of out_record_channel
]
(** The [local_receiver] is the object that gets the data received
* over the data connection.
*
* Page structure is not supported.
*)
type local_sender =
[ `File_structure of Netchannels.in_obj_channel
| `Record_structure of in_record_channel
]
(** The [local_sender] is the object that provides the data sent
* over the data connection.
*
* Page structure is not supported.
*)
type transmission_mode =
[ `Stream_mode
| `Block_mode
]
(** The transmission mode as described in RFC 959.
* Compressed mode is not supported.
*)
type descr_state =
[ `Clean
| `Transfer_in_progress
| `Down
]
(** Describes the state of the socket used for data transfers.
* The state [`Clean] means that a new data transfer may be started,
* either because the socket is new, or the last block transfer was
* properly finished. The state [`Transfer_in_progress] means that
* data is being transferred, but also that the transfer is aborted.
* The state [`Down] means that the socket is already at least half-closed,
* i.e. EOF was sent in one direction.
*)
type text_data_repr =
[ `ASCII of Netconversion.encoding
| `ASCII_unix of Netconversion.encoding
| `EBCDIC of Netconversion.encoding
]
(** Possible representation of text data:
* [`ASCII] means an ASCII-compatible encoding where the newline
* character is represented by CR/LF. [`ASCII_unix] is the same
* but newline is only LF. [`EBCDIC] is an EBCDIC variant.
*
* The argument specifies the exact variant to be used, e.g.
* [`ASCII `Enc_iso88591] or [`EBCDIC `Enc_cp1047].
*
* It is illegal to use [`ASCII] or [`ASCII_unix] with an ASCII-
* incompatible encoding, as well as combining [`EBCDIC] with a
* non-EBCDIC encoding. Wrong conversions would be the result of
* this.
*)
(* *********************************************************************)
(** {1 Data Stream Converters} *)
class write_out_record_channel :
repr:text_data_repr ->
Netchannels.out_obj_channel ->
out_record_channel
(** Provides an [out_record_channel] that represents EOR as
* newline character.
*
* @param repr Determines the newline character to use
*)
class read_in_record_channel :
repr:text_data_repr ->
Netchannels.in_obj_channel ->
in_record_channel
(** Provides an [in_record_channel] that takes newline characters as
* EOR representation.
*
* In this implementation, [input_line] can be used to read the full
* contents of a record (=line). However, [input_line] does not
* switch to the next record.
*
* @param repr Determines the newline character to use
*)
class data_converter :
fromrepr:text_data_repr -> torepr:text_data_repr ->
Netchannels.io_obj_channel
(** Creates a data conversion pipe converting [fromrepr] to
* [torepr].
*
* For simplicity, in an [`ASCII] input stream the CR characters are
* discarded, and the LF characters are taken as newline characters.
* In an output [`ASCII] stream, the CR/LF sequence is correctly
* created for newline characters.
*)
(* *********************************************************************)
(** {1 Engines} *)
(** The common type of FTP data engines *)
class type ftp_data_engine =
object
inherit [unit] Uq_engines.engine
method descr : Unix.file_descr
(** The socket to use for data transfers. This class never closes
* this socket, but it may be shut down at least partially.
*)
method descr_state : descr_state
(** The socket state *)
end
(** This engine receives data on a FTP data connection, and forwards
* them to a local receiver. The socket must already be open.
*
* It is ensured that [local_receiver] is always closed after operation
* (whether successful or not). The socket [descr] remains open.
*
* [tls]: may be set to [(config, peer_name, resume_data)]
*)
class ftp_data_receiver :
?tls:((module Netsys_crypto_types.TLS_CONFIG) *
string option *
string option) ->
?protector:ftp_protector ->
esys:Unixqueue.event_system ->
mode:transmission_mode ->
local_receiver:local_receiver ->
descr:Unix.file_descr ->
timeout:float ->
timeout_exn:exn ->
unit ->
object
inherit ftp_data_engine
method local_receiver : local_receiver
(** The local receiver. It is closed when the logical EOF is found in the
* data connection
*)
end
(** This engine sends data over a FTP data connection coming from
* a local sender. The socket must already be open.
*
* It is ensured that [local_sender] is always closed after operation
* (whether successful or not). The socket [descr] remains open.
*
* [tls]: may be set to [(config, peer_name, resume_data)]
*)
class ftp_data_sender :
?tls:((module Netsys_crypto_types.TLS_CONFIG) *
string option *
string option) ->
?protector:ftp_protector ->
esys:Unixqueue.event_system ->
mode:transmission_mode ->
local_sender:local_sender ->
descr:Unix.file_descr ->
timeout:float ->
timeout_exn:exn ->
unit ->
object
inherit ftp_data_engine
method local_sender : local_sender
(** The local sender. It is closed after usage.
*)
end