(*---------------------------------------------------------------------------*
  INTERFACE  cf_nameinfo.mli

  Copyright (c) 2003-2006, James H. Woodyatt
  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

    Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

    Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  OF THE POSSIBILITY OF SUCH DAMAGE. 
 *---------------------------------------------------------------------------*)

(** Domain name resolver interface. *)

(** {6 Overview}

    This module is a wrapper over the C interface to the Domain Name Resolver
    for IPv6 hosts.  These functions typically block until network resources
    respond to remote queries, sometimes within a few milliseconds.  Some
    exceptions are associated with conditions that take several seconds to
    detect, e.g. no domain name service available.
    
    Two functions are defined: [to_address] and [of_address].  Each function
    takes an optional argument in the form of a record of boolean flags to
    control the parameters of the query, much in the way the C interface to
    the [getaddrinfo()] and [getnameinfo()] functions work.

    Exceptions raised by the [to_address] and [of_address] functions are all
    of variants of type [unresolved] constructed on the exception
    [Unresolved] defined below.
*)

(** The sum type of exception conditions *)
type unresolved =
    | EAI_ADDRFAMILY        (** Address family not supported for node. *)
    | EAI_AGAIN             (** Temporary failure in name resolution. *)
    | EAI_BADFLAGS          (** Invalid value for flags. *)
    | EAI_FAIL              (** Non-recoverable failure in name resolution. *)
    | EAI_FAMILY            (** Address family not supported by resolver. *)
    | EAI_MEMORY            (** Memory allocation failure. *)
    | EAI_NODATA            (** No address associated with name. *)
    | EAI_NONAME            (** No name associated with address. *)
    | EAI_SERVICE           (** Service name not supported for socket type. *)
    | EAI_SOCKTYPE          (** Socket type not supported. *)
    | EAI_BADHINTS          (** Bad hints in getaddrinfo(). *)
    | EAI_PROTOCOL          (** Protocol not supported. *)
    | EAI_UNKNOWN of int    (** Unknown error code. *)

(** The exception type. *)
exception Unresolved of unresolved

(** The unspecified socket protocol, used in composing hints. *)
module P: Cf_socket.P with type AF.tag = unit and type ST.tag = unit

(** Returns true if the socket types are equivalent. *)
val is_specific_socktype:
    unit Cf_socket.socktype -> 'st Cf_socket.socktype -> bool

(** Returns true if the socket address is of the specific domain. *)
val is_specific_domain: unit Cf_socket.sockaddr -> 'af Cf_socket.domain -> bool

(** Use [specialize_sockaddr sa d] to specialize a socket address [sa] from the
    unspecified (or unknown) address family into a socket address of the
    address family associated with the socket domain [d].  Raises [Not_found]
    if the socket address is not of the appropriate address family.
*)
val specialize_sockaddr:
    unit Cf_socket.sockaddr -> 'af Cf_socket.domain -> 'af Cf_socket.sockaddr

(** The type of flags used with the [of_address] function to control the
    parameters of queries for host and service names.
*)
type of_address_flags = {
    ni_nofqdn: bool;        (** Return only the nodename for local hosts. *)
    ni_numerichost: bool;   (** Return only the numeric form (no DNS query). *)
    ni_namereqd: bool;      (** Raise exception unless name in DNS. *)
    ni_numericserv: bool;   (** Return only the numeric form (no DNS query). *)
    ni_dgram: bool;         (** Use "udp" in getservbyname(). *)
}

(** The default value of flags for the [of_address] function below (all
    flags set to [false]).
*)
val of_address_default_flags: of_address_flags

(** Use [of_address ?host ?serv ?flags sa] to resolve the name of the host and
    the service associated with the socket address [sa].  If the [?host] or
    [?serv] parameters are provided, they are used as the maximum length of the
    returned host and/or service name, respectively.  Returns an pair of
    strings, the first is the host name and the second is the service name.
    Raises [Unix.Error] if there is an error.
*)
val of_address:
    ?host:int -> ?serv:int -> ?flags:of_address_flags ->
    'a Cf_socket.sockaddr -> string * string

(** The type of flags used with the [to_address] function to control the
    parameters of queries for host addresses and service numbers.
*)
type to_address_flags = {
    ai_passive: bool;       (** Return a socket address for a listener. *)
    ai_canonname: bool;     (** Return the canonical name. *)
    ai_numerichost: bool;   (** Require numeric input (no DNS query). *)
}

(** The default value of [ai_flags] record field for the hints provided to the
    [to_address] function below (all flags set to [false]).
*)
val to_address_default_flags: to_address_flags

(** The argument to the [to_address] function. *)
type to_address_arg =
    | A_nodename of string              (** Unspecified service name. *)
    | A_servicename of string           (** Unspecified host name. *)
    | A_bothnames of string * string    (** Host and service names. *)

(** The type of elements in the list returned by the [to_address] function. *)
type ('af, 'st) addrinfo = private {
    ai_flags: to_address_flags;             (** Query control in hints. *)
    ai_family: 'af Cf_socket.domain;        (** The socket address family. *)
    ai_socktype: 'st Cf_socket.socktype;    (** The socket type. *)
    ai_protocol: Cf_socket.protocol;        (** The socket protocol. *)
    ai_cname: string option;                (** The canonical name. *)
    ai_addr: 'af Cf_socket.sockaddr;        (** The address. *)
}

(** Construct a hints value for the [to_address] function. *)
val addrinfo_hint:
    ?flags:to_address_flags -> 'af Cf_socket.domain ->
    'st Cf_socket.socktype -> Cf_socket.protocol -> ('af, 'st) addrinfo

(** The default hints value for the [to_address] function, . *)
val addrinfo_default_hint: (unit, unit) addrinfo

(** Use [to_addresses hint arg] to obtain a list of address information records
    associated with the host name and/or service name provided in the argument
    [arg], using the hints provided in the [hint] argument.
*)
val to_addresses:
    ('af, 'st) addrinfo -> to_address_arg -> ('af, 'st) addrinfo list

(** Use [to_all_address arg] to obtain a list of address information records
    associated with the host name and/or service name provided in the argument
    [arg].  The default hints are used.
*)
val to_all_addresses: to_address_arg -> (unit, unit) addrinfo list

(*--- End of File [ cf_nameinfo.mli ] ---*)
