(* $Id: uq_resolver.ml 1662 2011-08-29 23:05:06Z gerd $ *) type 't engine_state = [ `Working of int | `Done of 't | `Error of exn | `Aborted ] class type [ 't ] engine = object method state : 't engine_state method abort : unit -> unit method request_notification : (unit -> bool) -> unit method event_system : Unixqueue.event_system end exception Host_not_found of string class type resolver = object method host_by_name : string -> Unixqueue.event_system -> Unix.host_entry engine end let host_by_addr host = let l = String.length host in let addr = if l >= 2 && host.[0] = '[' && host.[l-1] = ']' then Unix.inet_addr_of_string (String.sub host 1 (l-2)) else Unix.inet_addr_of_string host in `Done { Unix.h_name = host; h_aliases = [| |]; h_addrtype = Netsys.domain_of_inet_addr addr; h_addr_list = [| addr |] } let default_resolver() : resolver = object (self) method host_by_name host esys = let state = try host_by_addr host with | Failure _ -> try let he = Unix.gethostbyname host in (`Done he) with Not_found -> (`Error(Host_not_found host)) in ( object method state = state method abort() = () method request_notification _ = () method event_system = esys end ) end let gai_resolver ?(ipv4=true) ?(ipv6=true) () : resolver = object (self) method host_by_name host esys = let state = try host_by_addr host with | Failure _ -> try let fam_flags = match ipv4, ipv6 with | false, false -> raise Not_found | true, false -> [ Unix.AI_FAMILY Unix.PF_INET ] | false, true -> [ Unix.AI_FAMILY Unix.PF_INET6 ] | true, true -> [] in let l = Unix.getaddrinfo host "" (Unix.AI_SOCKTYPE Unix.SOCK_STREAM :: Unix.AI_CANONNAME :: fam_flags) in match l with | [] -> raise Not_found | ai :: _ -> `Done { Unix.h_name = ai.Unix.ai_canonname; h_aliases = [| |]; h_addrtype = ai.Unix.ai_family; h_addr_list = Array.of_list (List.map (fun ai1 -> match ai1.Unix.ai_addr with | Unix.ADDR_INET(ip,_) -> ip | _ -> assert false ) (List.filter (fun ai1 -> ai1.Unix.ai_family = ai.Unix.ai_family) l ) ) } with Not_found -> (`Error(Host_not_found host)) in ( object method state = state method abort() = () method request_notification _ = () method event_system = esys end ) end let cur_resolver = ref(default_resolver()) let current_resolver() = !cur_resolver let set_current_resolver r = cur_resolver := r let get_host_by_name ?(resolver = !cur_resolver) host = let esys = Unixqueue.create_unix_event_system() in let eng = resolver # host_by_name host esys in let eng_final = ref false in try Unixqueue.run esys; ( match eng#state with | `Done he -> he | `Error e -> eng_final := true; raise e | _ -> assert false ) with | e when not !eng_final -> eng # abort(); raise e let sockaddr_of_socksymbol ?resolver = function | `Inet(ip,port) -> Unix.ADDR_INET(ip,port) | `Unix p -> Unix.ADDR_UNIX p | `Inet_byname(n,port) -> let e = get_host_by_name ?resolver n in let ip = e.Unix.h_addr_list.(0) in Unix.ADDR_INET(ip,port)