123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103(*
* Copyright (c) 2014 Anil Madhavapeddy <anil@recoil.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)openLwt.Infixletdebug=reffalseletdebug_print=refPrintf.eprintflet()=tryignore(Sys.getenv"CONDUIT_DEBUG");debug:=truewithNot_found->()letreturn_endpnamesvcuriendp=if!debugthen!debug_print"Resolver %s: %s %s -> %s\n%!"name(Uri.to_stringuri)(Sexplib0.Sexp.to_string_hum(Resolver.sexp_of_servicesvc))(Sexplib0.Sexp.to_string_hum(Conduit.sexp_of_endpendp));Lwt.returnendpletis_tls_service=(* TODO fill in the blanks. nowhere else to get this information *)function|"https"|"imaps"->true|_->falseletsystem_servicename=(* TODO memoize *)Lwt.catch(fun()->Lwt_unix.getservbynamename"tcp">>=funs->lettls=is_tls_servicenameinletsvc={Resolver.name;port=s.Lwt_unix.s_port;tls}inLwt.return(Somesvc))(functionNot_found->Lwt.return_none|e->Lwt.reraisee)letstatic_servicename=matchUri_services.tcp_port_of_servicenamewith|[]->Lwt.return_none|port::_->lettls=is_tls_servicenameinletsvc={Resolver.name;port;tls}inLwt.return(Somesvc)letget_hosturi=matchUri.hosturiwith|None->"localhost"|Somehost->(matchIpaddr.of_stringhostwith|Okip->Ipaddr.to_stringip|Error_->host)letget_portserviceuri=matchUri.porturiwithNone->service.Resolver.port|Someport->port(* Build a default resolver that uses the system gethostbyname and
the /etc/services file *)letsystem_resolverserviceuri=letopenLwt_unixinlethost=get_hosturiinletport=get_portserviceuriingetaddrinfohost(string_of_intport)[AI_SOCKTYPESOCK_STREAM]>>=funaddrinfos->(* In case both IPv4 and IPv6 addresses exist, favor IPv4: *)letv4,rest=List.partition(funi->i.ai_family=PF_INET)addrinfosinmatchList.rev_appendv4restwith|[]->return_endp"system"serviceuri(`Unknown"name resolution failed")|{ai_addr=ADDR_INET(addr,port);_}::_->return_endp"system"serviceuri(`TCP(Ipaddr_unix.of_inet_addraddr,port))|{ai_addr=ADDR_UNIXfile;_}::_->return_endp"system"serviceuri(`Unix_domain_socketfile)letstatic_resolverhostsserviceuri=tryreturn_endp"static"serviceuri(Hashtbl.findhosts(get_hosturi))withNot_found->return_endp"static"serviceuri(`Unknown"name resolution failed")letsystem=letservice=system_serviceinletrewrites=[("",system_resolver)]inResolver_lwt.init~service~rewrites()(* Build a default resolver from a static set of lookup rules *)letstatichosts=letservice=static_serviceinletrewrites=[("",static_resolverhosts)]inResolver_lwt.init~service~rewrites()