Skip to content
This repository was archived by the owner on May 22, 2018. It is now read-only.

Commit 0409955

Browse files
committed
Merge pull request #147 from euanh/CA-89974
CA-89974: Live migrate fails on IPv6-preferring hosts
2 parents 20dcb3a + 32fbe66 commit 0409955

File tree

6 files changed

+57
-22
lines changed

6 files changed

+57
-22
lines changed

http-svr/http.ml

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
open Stringext
1818
open Pervasiveext
19+
open Fun
1920

2021
exception Http_parse_failure
2122
exception Unauthorised of string
@@ -572,12 +573,19 @@ module Url = struct
572573
type t = scheme * data
573574

574575
let of_string url =
575-
let host x = match String.split ':' x with
576-
| host :: _ -> host
577-
| _ -> failwith (Printf.sprintf "Failed to parse host: %s" x) in
578-
let port x = match String.split ':' x with
579-
| _ :: port :: _ -> Some (int_of_string port)
580-
| _ -> None in
576+
let host x =
577+
let open String in
578+
try x |> sub_after '[' |> sub_before ']' with Not_found -> (* [<ipv6-literal>]... *)
579+
try x |> sub_before ':' with Not_found -> (* <hostname|ipv4-literal>:... *)
580+
x in (* <hostname|ipv4-literal> *)
581+
let port x =
582+
let port_part =
583+
let open String in
584+
try x |> sub_after ']' |> sub_after ':' with Not_found -> (* ...]:port *)
585+
try x |> sub_after ']' with Not_found -> (* ...] *)
586+
try x |> sub_after ':' with Not_found -> (* ...:port *)
587+
"" in (* no port *)
588+
try Some (int_of_string port_part) with _ -> None in
581589
let uname_password_host_port x = match String.split '@' x with
582590
| [ _ ] -> None, host x, port x
583591
| [ uname_password; host_port ] ->
@@ -608,6 +616,10 @@ module Url = struct
608616
let params = if params = [] then "" else "?" ^ (kvpairs params) in
609617
uri ^ params
610618

619+
(* Wrap a literal IPv6 address in square brackets; otherwise pass through *)
620+
let maybe_wrap_IPv6_literal addr =
621+
if Unixext.domain_of_addr addr = Some Unix.PF_INET6 then "[" ^ addr ^ "]" else addr
622+
611623
let to_string = function
612624
| File { path = path }, data -> Printf.sprintf "file:%s%s" path (data_to_string data) (* XXX *)
613625
| Http h, data ->
@@ -618,7 +630,7 @@ module Url = struct
618630
| Some x -> Printf.sprintf ":%d" x
619631
| _ -> "" in
620632
Printf.sprintf "http%s://%s%s%s%s" (if h.ssl then "s" else "")
621-
userpassat h.host colonport (data_to_string data)
633+
userpassat (maybe_wrap_IPv6_literal h.host) colonport (data_to_string data)
622634

623635
let get_uri (scheme, data) = data.uri
624636
let set_uri (scheme, data) u = (scheme, { data with uri = u })

http-svr/http.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ module Url : sig
191191

192192
val of_string: string -> t
193193

194+
(** Wrap a literal IPv6 address in square brackets; otherwise pass through *)
195+
val maybe_wrap_IPv6_literal : string -> string
196+
194197
val to_string: t -> string
195198

196199
val get_uri: t -> string

stdext/stringext.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,10 @@ let sub_to_end s start =
214214
let length = String.length s in
215215
String.sub s start (length - start)
216216

217+
let sub_before c s =
218+
String.sub s 0 (String.index s c)
219+
220+
let sub_after c s =
221+
sub_to_end s (String.index s c + 1)
222+
217223
end

stdext/stringext.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,10 @@ module String :
120120

121121
(** a substring from the specified position to the end of the string *)
122122
val sub_to_end : string -> int -> string
123+
124+
(** a substring from the start of the string to the first occurrence of a given character, excluding the character *)
125+
val sub_before : char -> string -> string
126+
127+
(** a substring from the first occurrence of a given character to the end of the string, excluding the character *)
128+
val sub_after : char -> string -> string
123129
end

stdext/unixext.ml

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -252,21 +252,19 @@ let delete_empty_file file_path =
252252
(** Create a new file descriptor, connect it to host:port and return it *)
253253
exception Host_not_found of string
254254
let open_connection_fd host port =
255-
let s = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
256-
try
257-
let he =
258-
try
259-
Unix.gethostbyname host
260-
with
261-
Not_found -> raise (Host_not_found host) in
262-
if Array.length he.Unix.h_addr_list = 0
263-
then failwith (Printf.sprintf "Couldn't resolve hostname: %s" host);
264-
let ip = he.Unix.h_addr_list.(0) in
265-
let addr = Unix.ADDR_INET(ip, port) in
266-
Unix.connect s addr;
267-
s
268-
with e -> Unix.close s; raise e
269-
255+
let open Unix in
256+
let addrinfo = getaddrinfo host (string_of_int port) [AI_SOCKTYPE SOCK_STREAM] in
257+
match addrinfo with
258+
| [] ->
259+
failwith (Printf.sprintf "Couldn't resolve hostname: %s" host)
260+
| ai :: _ ->
261+
let s = socket ai.ai_family ai.ai_socktype 0 in
262+
try
263+
connect s ai.ai_addr;
264+
s
265+
with e ->
266+
close s;
267+
raise e
270268

271269
let open_connection_unix_fd filename =
272270
let s = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in
@@ -677,6 +675,13 @@ type statvfs_t = {
677675

678676
external statvfs : string -> statvfs_t = "stub_statvfs"
679677

678+
(** Returns Some Unix.PF_INET or Some Unix.PF_INET6 if passed a valid IP address, otherwise returns None. *)
679+
let domain_of_addr str =
680+
try
681+
let addr = Unix.inet_addr_of_string str in
682+
Some (Unix.domain_of_sockaddr (Unix.ADDR_INET (addr, 1)))
683+
with _ -> None
684+
680685
module Direct = struct
681686
type t = Unix.file_descr
682687

stdext/unixext.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ type statvfs_t = {
167167

168168
val statvfs : string -> statvfs_t
169169

170+
(** Returns Some Unix.PF_INET or Some Unix.PF_INET6 if passed a valid IP address, otherwise returns None. *)
171+
val domain_of_addr : string -> Unix.socket_domain option
172+
170173
module Direct : sig
171174
(** Perform I/O in O_DIRECT mode using 4KiB page-aligned buffers *)
172175

0 commit comments

Comments
 (0)