Can those with more experience in OCaml please take a look over this and tell me if I'm heading down the right path?
This patch theoretically adds support for IPv6 in recon; it adds the settings hooks for hkp too, but doesn't add anything that uses that yet. It should both listen on IPv6 and connect outbound too. It compiles. It runs. I see both listening sockets with lsof. It doesn't do anything soon enough for me to see tonight how well I've done, as I need to go get some sleep. I'm not sufficiently comfortable to leave sks-peer.spodhuis.org running this code overnight, so I've reverted to 1.1.0. It's my first OCaml hacking and my style sucks and I spend more time debugging to get it to compile than I care to think about. A critical eye and constructive comments appreciated. Oh, and I've no idea how recent support for IPv6 in OCaml is and have made no effort to gracefully degrade to either old OCaml environments or systems without IPv6 support. First, I want to get it working for anyone, *then* I can worry about making it conditional. Thanks, -Phil
diff -r e30dc5376cbb common.ml --- a/common.ml Fri May 23 21:16:40 2008 -0400 +++ b/common.ml Mon Mar 02 02:43:24 2009 -0800 @@ -199,6 +199,7 @@ let recon_port = !Settings.recon_port let recon_address = !Settings.recon_address +let recon6_address = !Settings.recon6_address let http_port = !Settings.hkp_port let http_address = !Settings.hkp_address let db_command_name = Filename.concat !Settings.basedir "db_com_sock" @@ -212,7 +213,15 @@ | Unix.ADDR_INET (inet_addr,port) -> Unix.ADDR_INET (inet_addr,port + 1) -let get_client_recon_addr () = - Unix.ADDR_INET (Unix.inet_addr_of_string recon_address,0) +let get_client_recon_addr remote_addr = match Unix.domain_of_sockaddr remote_addr with + Unix.PF_UNIX -> failwith "Can't connect to remote local-domain sockets" + | Unix.PF_INET -> Unix.ADDR_INET (Unix.inet_addr_of_string recon_address,0) + | Unix.PF_INET6 -> Unix.ADDR_INET (Unix.inet_addr_of_string recon6_address,0) let get_client_recon_addr = - Utils.unit_memoize get_client_recon_addr + Utils.memoize get_client_recon_addr + +let sockaddr_to_string sockaddr = match sockaddr with + Unix.ADDR_UNIX s -> sprintf "<ADDR_UNIX %s>" s + | Unix.ADDR_INET (addr,p) -> sprintf "<ADDR_INET %s:%d>" + (Unix.string_of_inet_addr addr) p + diff -r e30dc5376cbb eventloop.ml --- a/eventloop.ml Fri May 23 21:16:40 2008 -0400 +++ b/eventloop.ml Mon Mar 02 02:43:24 2009 -0800 @@ -121,10 +121,7 @@ let create_sock addr = try - let domain = - match addr with - ADDR_UNIX _ -> PF_UNIX - | ADDR_INET (_,_) -> PF_INET in + let domain = Unix.domain_of_sockaddr addr in let sock = socket ~domain ~kind:SOCK_STREAM ~protocol:0 in setsockopt sock SO_REUSEADDR true; @@ -132,8 +129,10 @@ listen sock ~max:20; sock with - | Unix_error (_,"bind",_) -> - failwith "Failure while binding socket. Probably another socket bound to this address" + | Unix_error (error, "bind",_) -> + let msg = error_message error in + let addrstr = sockaddr_to_string addr in + failwith (sprintf "Failure binding %s: %s" addrstr msg) | e -> raise e let add_events heap evlist = List.iter ~f:(fun (Event (time, callback)) -> diff -r e30dc5376cbb membership.ml --- a/membership.ml Fri May 23 21:16:40 2008 -0400 +++ b/membership.ml Mon Mar 02 02:43:24 2009 -0800 @@ -29,28 +29,80 @@ exception Bug of string exception Lookup_failure of string exception Malformed_entry of string +exception Empty_line let membership = ref ([| |],-1.) let whitespace = Str.regexp "[ \t]+" -let lookup_hostname string = - try (Unix.gethostbyname string).Unix.h_addr_list.(0) - with +(* Although the OCaml standard Unix library does not include AF_UNSPEC, the + * underlying C implementation uses AF_UNSPEC unless overriden (ie, there's + * no way to specify a value which matches the default behaviour). + * So for IPv4/IPv6 functionality, use getaddrinfo without an AI_FAMILY + * parameter. + * This does mean that we need a separate function to filter though. + *) + +let inet_addr_of_sockaddr sock = match sock with + Unix.ADDR_UNIX _ -> raise (Bug "asking for inet addr of local domain socket") + | Unix.ADDR_INET (addr, port) -> addr + +let inet_addr_of_addr_info ai = match ai.Unix.ai_addr with + Unix.ADDR_UNIX _ -> raise (Bug "converting getaddrinfo result which is local domain?") + | Unix.ADDR_INET (addr, port) -> addr + +let lookup_hostname_list ?(port = recon_port) string = + let portstr = string_of_int port in + try begin + let reslist = Unix.getaddrinfo string portstr [Unix.AI_SOCKTYPE Unix.SOCK_STREAM] in + if List.length reslist == 0 then raise (Lookup_failure string) + else List.map inet_addr_of_addr_info reslist + end + with | Invalid_argument _ | Not_found -> raise (Lookup_failure string) -let local_recon_addr () = - Unix.ADDR_INET (lookup_hostname !Settings.hostname, recon_port) +let lookup_hostname_list_filtered ~family ?(port = recon_port) string = + let portstr = string_of_int port in + let filter = (fun ai -> if ai.Unix.ai_family == family then true else false) in + try begin + let reslist = Unix.getaddrinfo string portstr [Unix.AI_SOCKTYPE Unix.SOCK_STREAM] in + if List.length reslist == 0 then raise (Lookup_failure string) + else List.map inet_addr_of_addr_info (List.filter filter reslist) + end + with + | Invalid_argument _ | Not_found -> raise (Lookup_failure string) -let local_recon_addr = Utils.unit_memoize local_recon_addr +let my_ipv4_recon_addresses () = + let r = Unix.inet_addr_of_string !Settings.recon_address in + if r = Unix.inet_addr_any + then lookup_hostname_list_filtered ~family:Unix.PF_INET !Settings.hostname + else [r] +let my_ipv4_recon_addresses = Utils.unit_memoize my_ipv4_recon_addresses + +let my_ipv6_recon_addresses () = + let r = Unix.inet_addr_of_string !Settings.recon6_address in + if r = Unix.inet6_addr_any + then lookup_hostname_list_filtered ~family:Unix.PF_INET6 !Settings.hostname + else [r] +let my_ipv6_recon_addresses = Utils.unit_memoize my_ipv6_recon_addresses + +let is_local_recon_addr peer = match Unix.domain_of_sockaddr peer with + Unix.PF_UNIX -> raise (Bug "trying to find local address of remote local domain socket") + | Unix.PF_INET -> List.exists (fun a -> (inet_addr_of_sockaddr peer) = a) (my_ipv4_recon_addresses ()) + | Unix.PF_INET6 -> List.exists (fun a -> (inet_addr_of_sockaddr peer) = a) (my_ipv6_recon_addresses ()) + +let is_local_recon_addr = Utils.memoize is_local_recon_addr let remove_self addresses = - List.filter ~f:(fun (addr,str) -> addr <> local_recon_addr ()) addresses + List.filter ~f:(fun (addr,str) -> not (is_local_recon_addr addr)) addresses +(* For now, leave this single-address *) let convert_address l = try - sscanf l "%s %d" - (fun addr port -> Unix.ADDR_INET (lookup_hostname addr,port)) + if String.length l == 0 then raise Empty_line + else + sscanf l "%s %d" + (fun addr port -> Unix.ADDR_INET (List.hd (lookup_hostname_list addr),port)) with Scanf.Scan_failure _ | End_of_file | Failure _ -> raise (Malformed_entry l) @@ -61,6 +113,7 @@ let addr = convert_address line in (addr,line) :: loop list with + | Empty_line -> loop list | End_of_file -> list | Lookup_failure addr -> perror "Lookup failure on address %s" addr; @@ -93,11 +146,6 @@ ) ~finally:(fun () -> close_in file) -let sockaddr_to_string sockaddr = match sockaddr with - Unix.ADDR_UNIX s -> sprintf "<ADDR_UNIX %s>" s - | Unix.ADDR_INET (addr,p) -> sprintf "<ADDR_INET %s:%d>" - (Unix.string_of_inet_addr addr) p - let membership_string () = let (mshp,_) = !membership in let to_string (addr,str) = diff -r e30dc5376cbb reconCS.ml --- a/reconCS.ml Fri May 23 21:16:40 2008 -0400 +++ b/reconCS.ml Mon Mar 02 02:43:24 2009 -0800 @@ -129,7 +129,7 @@ (** function to connect to remote host to initate reconciliation *) -let connect tree ~filters ~partner ~self = +let connect tree ~filters ~partner = (* TODO: change the following to depend on the address type *) let s = Unix.socket ~domain:Unix.PF_INET @@ -137,7 +137,7 @@ ~protocol:0 in let run () = - Unix.bind s ~addr:(get_client_recon_addr ()); + Unix.bind s ~addr:(get_client_recon_addr partner); Unix.connect s ~addr:partner; let cin = Channel.sys_in_from_fd s and cout = Channel.sys_out_from_fd s in diff -r e30dc5376cbb reconComm.ml --- a/reconComm.ml Fri May 23 21:16:40 2008 -0400 +++ b/reconComm.ml Mon Mar 02 02:43:24 2009 -0800 @@ -67,11 +67,11 @@ let get_keystrings_via_http addr hashes = let s = Unix.socket - ~domain:Unix.PF_INET + ~domain:(Unix.domain_of_sockaddr addr) ~kind:Unix.SOCK_STREAM ~protocol:0 in protect ~f:(fun () -> - Unix.bind s ~addr:(get_client_recon_addr ()); + Unix.bind s ~addr:(get_client_recon_addr addr); Unix.connect s ~addr; let cin = Channel.sys_in_from_fd s and cout = Channel.sys_out_from_fd s in diff -r e30dc5376cbb reconserver.ml --- a/reconserver.ml Fri May 23 21:16:40 2008 -0400 +++ b/reconserver.ml Mon Mar 02 02:43:24 2009 -0800 @@ -50,7 +50,9 @@ (******************************************************************) let recon_addr = Unix.ADDR_INET (Unix.inet_addr_of_string recon_address,recon_port) + let recon6_addr = Unix.ADDR_INET (Unix.inet_addr_of_string recon6_address,recon_port) let reconsock = Eventloop.create_sock recon_addr + let recon6sock = Eventloop.create_sock recon6_addr let () = if Sys.file_exists recon_command_name @@ -215,7 +217,6 @@ let filters = get_filters () in let (results,http_addr) = ReconCS.connect (get_ptree ()) ~filters ~partner - ~self:Membership.local_recon_addr in let results = ZSet.elements results in plerror 4 "Reconciliation complete"; @@ -360,7 +361,12 @@ ~timeout:!Settings.command_timeout ); (reconsock, Eventloop.make_th - ~name:"reconciliation handler" + ~name:"reconciliation handler (IPv4)" + ~cb:recon_handler + ~timeout:!Settings.reconciliation_config_timeout + ); + (recon6sock, Eventloop.make_th + ~name:"reconciliation handler (IPv6)" ~cb:recon_handler ~timeout:!Settings.reconciliation_config_timeout ); diff -r e30dc5376cbb settings.ml --- a/settings.ml Fri May 23 21:16:40 2008 -0400 +++ b/settings.ml Mon Mar 02 02:43:24 2009 -0800 @@ -56,12 +56,16 @@ seed := value let recon_port = ref 11370 -let recon_address = ref "0.0.0.0" +let recon_address = ref (Unix.string_of_inet_addr Unix.inet_addr_any) let set_recon_address value = recon_address := value +let recon6_address = ref (Unix.string_of_inet_addr Unix.inet6_addr_any) +let set_recon6_address value = recon6_address := value let hkp_port = ref 11371 -let hkp_address = ref "0.0.0.0" +let hkp_address = ref (Unix.string_of_inet_addr Unix.inet_addr_any) let set_hkp_address value = hkp_address := value +let hkp6_address = ref (Unix.string_of_inet_addr Unix.inet6_addr_any) +let set_hkp6_address value = hkp6_address := value let use_port_80 = ref false @@ -247,9 +251,11 @@ ("-baseport",Arg.Int set_base_port, " Set base port number"); ("-logfile",Arg.String (fun _ -> ()), " DEPRECATED. Now ignored."); ("-recon_port",Arg.Int set_recon_port, " Set recon port number"); - ("-recon_address",Arg.String set_recon_address, " Set recon binding address"); + ("-recon_address",Arg.String set_recon_address, " Set recon binding address (IPv4)"); + ("-recon6_address",Arg.String set_recon6_address, " Set recon binding address (IPv6)"); ("-hkp_port",Arg.Int set_hkp_port, " Set hkp port number"); - ("-hkp_address",Arg.String set_hkp_address, " Set hkp binding address"); + ("-hkp_address",Arg.String set_hkp_address, " Set hkp binding address (IPv4)"); + ("-hkp6_address",Arg.String set_hkp6_address, " Set hkp binding address (IPv6)"); ("-use_port_80",Arg.Set use_port_80, " Have the HKP interface listen on port 80, as well as the hkp_port"); ("-basedir", Arg.Set_string basedir, " Base directory"); diff -r e30dc5376cbb sks.pod --- a/sks.pod Fri May 23 21:16:40 2008 -0400 +++ b/sks.pod Mon Mar 02 02:43:24 2009 -0800 @@ -152,7 +152,11 @@ =item -recon_address -Set recon binding address. +Set recon binding IPv4 address. Also used for outbound connections. + +=item -recon6_address + +Set recon binding IPv6 address. Also used for outbound connections. =item -hkp_port @@ -160,7 +164,11 @@ =item -hkp_address -Set hkp binding address. +Set hkp binding IPv4 address. + +=item -hkp6_address + +Set hkp binding IPv6 address. =item -use_port_80
pgp4iieTr8DB7.pgp
Description: PGP signature
_______________________________________________ Sks-devel mailing list Sks-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/sks-devel