[Unison-hackers] ipv6 support

Samuel Thibault samuel.thibault at ens-lyon.org
Sat Jul 16 07:44:05 EDT 2005


Hi,

Here are patches for ipv6 support: just using getaddrinfo instead of
gethostbyname, and it works nicely. I turned ports into strings, so as
to be able to use port names too.

patch-unison is for version 2.9.1, patch-unison-svn is against current
subversion repository.

Regards,
Samuel
-------------- next part --------------
diff -ur unison-2.9.1/main.ml unison-2.9.1-mine/main.ml
--- unison-2.9.1/main.ml	2002-04-11 07:13:23.000000000 +0200
+++ unison-2.9.1-mine/main.ml	2005-03-30 02:15:01.000000000 +0200
@@ -174,15 +174,7 @@
 
 (* Start a socket server if requested *)
 begin try
-  let i =
-    match Util.StringMap.find socketPrefName argv with
-      [] ->
-        assert false
-    | i::_ ->
-        try int_of_string i with Failure _ ->
-          Util.msg "-socket must be followed by a number\n";
-          exit 1
-  in
+  let i = List.hd (Util.StringMap.find socketPrefName argv) in
   catch_all (fun () ->
     Os.createUnisonDir();
     Remote.waitOnPort i);
diff -ur unison-2.9.1/remote.ml unison-2.9.1-mine/remote.ml
--- unison-2.9.1/remote.ml	2002-04-11 07:13:23.000000000 +0200
+++ unison-2.9.1-mine/remote.ml	2005-03-30 02:24:04.000000000 +0200
@@ -1037,25 +1037,24 @@
   Lwt.return conn))
 
 let buildSocketConnection host port =
-  let targetInetAddr =
-    try
-      let targetHostEntry = Unix.gethostbyname host in
-      targetHostEntry.Unix.h_addr_list.(0)
-    with Not_found ->
+  let rec loop = function
+    [] -> 
       raise (Util.Fatal
-               (Printf.sprintf
-                  "Can't find the IP address of the server (%s)" host))
-  in
-  (* create a socket to talk to the remote host *)
-  let socket = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
-  begin try
-    Unix.connect socket (Unix.ADDR_INET(targetInetAddr,port))
-  with
-    Unix.Unix_error (_, _, reason) ->
-      raise (Util.Fatal
-               (Printf.sprintf "Can't connect to server (%s): %s" host reason))
-  end;
-  Lwt_unix.run (initConnection socket socket)
+	       (Printf.sprintf
+		  "Can't find the IP address of the server (%s:%s)" host port))
+  | ai::r ->
+    (* create a socket to talk to the remote host *)
+    let socket = Unix.socket ai.Unix.ai_family ai.Unix.ai_socktype ai.Unix.ai_protocol in
+    begin try
+      Unix.connect socket ai.Unix.ai_addr;
+      Lwt_unix.run (initConnection socket socket)
+    with
+      Unix.Unix_error (_, _, reason) ->
+	(Util.warn
+	  (Printf.sprintf "Can't connect to server (%s:%s): %s" host port reason);
+	 loop r)
+    end
+  in loop (Unix.getaddrinfo host port [ Unix.AI_SOCKTYPE Unix.SOCK_STREAM ])
 
 let buildShellConnection shell host userOpt portOpt =
   let (in_ch, out_ch) =
@@ -1071,7 +1070,7 @@
     let portArgs =
       match portOpt with
         None -> []
-      | Some port -> ["-p"; string_of_int port] in
+      | Some port -> ["-p"; port] in
     let shellCmd =
       (if shell = "ssh" then
         Prefs.read sshCmd
@@ -1197,18 +1196,31 @@
 (* Used by the socket mechanism: Create a socket on portNum and wait
    for a request. Each request is processed by commandLoop. When a
    session finishes, the server waits for another request. *)
-let waitOnPort portnum =
+let waitOnPort port =
   Util.convertUnixErrorsToFatal
     "waiting on port"
     (fun () ->
-      (* Open a socket to listen for queries *)
-      let listening = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
-      (* Allow reuse of local addresses for bind *)
-      Unix.setsockopt listening Unix.SO_REUSEADDR true;
-      (* Bind the socket to portnum on the local host *)
-      Unix.bind listening (Unix.ADDR_INET(Unix.inet_addr_any,portnum));
-      (* Start listening, allow up to 1 pending request *)
-      Unix.listen listening 1;
+      let rec loop = function
+        [] -> raise (Util.Fatal
+		(Printf.sprintf "Can't find local port %s" port))
+      | ai::r ->
+	(* Open a socket to listen for queries *)
+        let socket = Unix.socket ai.Unix.ai_family ai.Unix.ai_socktype ai.Unix.ai_protocol in
+	begin try
+	  (* Allow reuse of local addresses for bind *)
+	  Unix.setsockopt socket Unix.SO_REUSEADDR true;
+	  (* Bind the socket to portnum on the local host *)
+	  Unix.bind socket ai.Unix.ai_addr;
+	  (* Start listening, allow up to 1 pending request *)
+	  Unix.listen socket 1;
+	  socket
+	with
+	  Unix.Unix_error (_, _, reason) ->
+	    (Util.warn
+	      (Printf.sprintf "Can't bind to local port (%s:%s): %s" ai.Unix.ai_canonname port reason);
+	     loop r)
+	end in
+      let listening = loop (Unix.getaddrinfo "" port [ Unix.AI_SOCKTYPE Unix.SOCK_STREAM ; Unix.AI_PASSIVE ]) in
       Util.msg "server started\n";
       while
         (* Accept a connection *)
diff -ur unison-2.9.1/remote.mli unison-2.9.1-mine/remote.mli
--- unison-2.9.1/remote.mli	2002-04-11 07:13:23.000000000 +0200
+++ unison-2.9.1-mine/remote.mli	2005-03-30 02:13:53.000000000 +0200
@@ -64,7 +64,7 @@
 (* Enter "server mode", reading and processing commands from a remote
    client process until killed *)
 val beAServer : unit -> unit
-val waitOnPort : int -> unit
+val waitOnPort : string -> unit
 
 (* Whether the server should be killed when the client terminates *)
 val killServer : bool Prefs.t
diff -ur unison-2.9.1/uigtk.ml unison-2.9.1-mine/uigtk.ml
--- unison-2.9.1/uigtk.ml	2002-04-11 07:13:23.000000000 +0200
+++ unison-2.9.1-mine/uigtk.ml	2005-03-30 01:58:19.000000000 +0200
@@ -655,21 +655,17 @@
       `Local ->
         Uri.clroot2string(Uri.ConnectLocal(Some file))
     | `SSH | `RSH ->
-        let portOpt =
-          (* FIX: report an error if the port entry is not well formed *)
-          try Some(int_of_string(portE#text))
-          with _ -> None in
         Uri.clroot2string(
         Uri.ConnectByShell((if !varLocalRemote=`SSH then "ssh" else "rsh"),
                            host,
                            (if user="" then None else Some user),
-                           portOpt,
+                           Some portE#text,
                            Some file))
     | `SOCKET ->
         Uri.clroot2string(
         (* FIX: report an error if the port entry is not well formed *)
         Uri.ConnectBySocket(host,
-                            int_of_string(portE#text),
+                            portE#text,
                             Some file)) in
   let contCommand() =
     try
diff -ur unison-2.9.1/uri.ml unison-2.9.1-mine/uri.ml
--- unison-2.9.1/uri.ml	2002-04-11 07:13:23.000000000 +0200
+++ unison-2.9.1-mine/uri.ml	2005-03-30 01:34:08.000000000 +0200
@@ -33,11 +33,11 @@
           string        (* shell = "rsh" or "ssh" *)
         * string        (* name of host *)
         * string option (* user name to log in as *)
-        * int option    (* port *)
+        * string option (* port *)
         * string option (* root of replica in host fs *)
   | ConnectBySocket of
           string        (* name of host *)
-        * int           (* port where server should be listening *)
+        * string        (* port where server should be listening *)
         * string option (* root of replica in host fs *)
 
 (* Internal datatypes used in parsing command-line roots *)
@@ -107,13 +107,13 @@
     (Some host,s')
   else (None,s)
 
-let colonPortRegexp = Str.regexp ":[0-9]+"
+let colonPortRegexp = Str.regexp ":[^/]+"
 let getPort s =
   if Str.string_match colonPortRegexp s 0
   then
     let colonPort = Str.matched_string s in
     let len = String.length colonPort in
-    let port = int_of_string(String.sub colonPort 1 (len-1)) in
+    let port = String.sub colonPort 1 (len-1) in
     let s' = Str.string_after s len in
     (Some port,s')
   else (None,s)
@@ -178,11 +178,11 @@
     else Printf.sprintf "file:///%s" s
     else s
 | ConnectBySocket(h,p,s) ->
-    Printf.sprintf "socket://%s:%d/%s" h p
+    Printf.sprintf "socket://%s:%s/%s" h p
       (match s with None -> "" | Some x -> x)
 | ConnectByShell(sh,h,u,p,s) ->
     let user = match u with None -> "" | Some x -> x^"@" in
-    let port = match p with None -> "" | Some x -> ":"^(string_of_int x) in
+    let port = match p with None -> "" | Some x -> ":"^x in
     let path = match s with None -> "" | Some x -> x in
     Printf.sprintf "%s://%s%s%s/%s" sh user h port path
 
diff -ur unison-2.9.1/uri.mli unison-2.9.1-mine/uri.mli
--- unison-2.9.1/uri.mli	2002-04-11 07:13:23.000000000 +0200
+++ unison-2.9.1-mine/uri.mli	2005-03-30 01:35:47.000000000 +0200
@@ -10,11 +10,11 @@
           string        (* shell = "rsh" or "ssh" *)
         * string        (* name of host *)
         * string option (* user name to log in as *)
-        * int option    (* port *)
+        * string option (* port *)
         * string option (* root of replica in host fs *)
   | ConnectBySocket of
           string        (* name of host *)
-        * int           (* port where server should be listening *)
+        * string        (* port where server should be listening *)
         * string option (* root of replica in host fs *)
 
 val clroot2string : clroot -> string
-------------- next part --------------
Index: remote.ml
===================================================================
--- remote.ml	(r?vision 92)
+++ remote.ml	(copie de travail)
@@ -811,25 +811,26 @@
 
 let buildSocketConnection host port =
   Util.convertUnixErrorsToFatal "canonizeRoot" (fun () ->
-    let targetInetAddr =
-      try
-        inetAddr host
-      with Not_found ->
+    let rec loop = function
+      [] ->
         raise (Util.Fatal
                  (Printf.sprintf
-                    "Can't find the IP address of the server (%s)" host))
-    in
-    (* create a socket to talk to the remote host *)
-    let socket = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
-    begin try
-      Unix.connect socket (Unix.ADDR_INET(targetInetAddr,port))
-    with
-      Unix.Unix_error (_, _, reason) ->
-        raise (Util.Fatal
-                 (Printf.sprintf
-                    "Can't connect to server (%s): %s" host reason))
-    end;
-    initConnection socket socket)
+                    "Can't find the IP address of the server (%s:%s)" host
+		    port))
+    | ai::r ->
+      (* create a socket to talk to the remote host *)
+      let socket = Unix.socket ai.Unix.ai_family ai.Unix.ai_socktype ai.Unix.ai_protocol in
+      begin try
+        Unix.connect socket ai.Unix.ai_addr;
+        initConnection socket socket
+      with
+        Unix.Unix_error (_, _, reason) ->
+          (Util.warn
+            (Printf.sprintf
+                    "Can't connect to server (%s:%s): %s" host port reason);
+           loop r)
+    end
+    in loop (Unix.getaddrinfo host port [ Unix.AI_SOCKTYPE Unix.SOCK_STREAM ]))
 
 let buildShellConnection shell host userOpt portOpt rootName termInteract =
   let remoteCmd =
@@ -844,7 +845,7 @@
   let portArgs =
     match portOpt with
       None -> []
-    | Some port -> ["-p"; string_of_int port] in
+    | Some port -> ["-p"; port] in
   let shellCmd =
     (if shell = "ssh" then
       Prefs.read sshCmd
@@ -980,7 +981,7 @@
         let portArgs =
           match portOpt with
             None -> []
-          | Some port -> ["-p"; string_of_int port] in
+          | Some port -> ["-p"; port] in
         let shellCmd =
           (if shell = "ssh" then
             Prefs.read sshCmd
@@ -1113,30 +1114,38 @@
 (* Used by the socket mechanism: Create a socket on portNum and wait
    for a request. Each request is processed by commandLoop. When a
    session finishes, the server waits for another request. *)
-let waitOnPort hostOpt portnum =
+let waitOnPort hostOpt port =
   Util.convertUnixErrorsToFatal
     "waiting on port"
     (fun () ->
-      (* Open a socket to listen for queries *)
-      let listening = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
-      (* Allow reuse of local addresses for bind *)
-      Unix.setsockopt listening Unix.SO_REUSEADDR true;
-      (* Bind the socket to portnum on the local host *)
-      let addr =
-        match hostOpt with
-          Some host ->
-            begin try inetAddr host with Not_found ->
-              raise (Util.Fatal
-                       (Printf.sprintf
-                          "Can't find the IP address of the host (%s)" host))
-            end
-        | None ->
-            Unix.inet_addr_any
-      in
-      Unix.bind listening
-        (Unix.ADDR_INET (addr, portnum));
-      (* Start listening, allow up to 1 pending request *)
-      Unix.listen listening 1;
+      let host = match hostOpt with
+        Some host -> host
+      | None -> "" in
+      let rec loop = function
+        [] -> raise (Util.Fatal
+		       (Printf.sprintf "Can't find host (%s:%s)" host port))
+      | ai::r ->
+        (* Open a socket to listen for queries *)
+        let socket = Unix.socket ai.Unix.ai_family ai.Unix.ai_socktype
+	  ai.Unix.ai_protocol in
+	begin try
+          (* Allow reuse of local addresses for bind *)
+          Unix.setsockopt socket Unix.SO_REUSEADDR true;
+          (* Bind the socket to portnum on the local host *)
+	  Unix.bind socket ai.Unix.ai_addr;
+          (* Start listening, allow up to 1 pending request *)
+          Unix.listen socket 1;
+	  socket
+	with
+	  Unix.Unix_error (_, _, reason) ->
+            (Util.warn
+               (Printf.sprintf
+                  "Can't bind to host (%s:%s): %s" ai.Unix.ai_canonname port
+		  reason);
+	     loop r)
+	end in
+      let listening = loop (Unix.getaddrinfo host port [ Unix.AI_SOCKTYPE
+        Unix.SOCK_STREAM ; Unix.AI_PASSIVE ]) in
       Util.msg "server started\n";
       while
         (* Accept a connection *)
Index: clroot.ml
===================================================================
--- clroot.ml	(r?vision 92)
+++ clroot.ml	(copie de travail)
@@ -33,11 +33,11 @@
           string        (* shell = "rsh" or "ssh" *)
         * string        (* name of host *)
         * string option (* user name to log in as *)
-        * int option    (* port *)
+        * string option (* port *)
         * string option (* root of replica in host fs *)
   | ConnectBySocket of
           string        (* name of host *)
-        * int           (* port where server should be listening *)
+        * string        (* port where server should be listening *)
         * string option (* root of replica in host fs *)
 
 (* Internal datatypes used in parsing command-line roots *)
@@ -107,13 +107,13 @@
     (Some host,s')
   else (None,s)
 
-let colonPortRegexp = Str.regexp ":[0-9]+"
+let colonPortRegexp = Str.regexp ":[^/]+"
 let getPort s =
   if Str.string_match colonPortRegexp s 0
   then
     let colonPort = Str.matched_string s in
     let len = String.length colonPort in
-    let port = int_of_string(String.sub colonPort 1 (len-1)) in
+    let port = String.sub colonPort 1 (len-1) in
     let s' = Str.string_after s len in
     (Some port,s')
   else (None,s)
@@ -178,11 +178,11 @@
     else Printf.sprintf "file:///%s" s
     else s
 | ConnectBySocket(h,p,s) ->
-    Printf.sprintf "socket://%s:%d/%s" h p
+    Printf.sprintf "socket://%s:%s/%s" h p
       (match s with None -> "" | Some x -> x)
 | ConnectByShell(sh,h,u,p,s) ->
     let user = match u with None -> "" | Some x -> x^"@" in
-    let port = match p with None -> "" | Some x -> ":"^(string_of_int x) in
+    let port = match p with None -> "" | Some x -> ":"^x in
     let path = match s with None -> "" | Some x -> x in
     Printf.sprintf "%s://%s%s%s/%s" sh user h port path
 
Index: clroot.mli
===================================================================
--- clroot.mli	(r?vision 92)
+++ clroot.mli	(copie de travail)
@@ -10,11 +10,11 @@
           string        (* shell = "rsh" or "ssh" *)
         * string        (* name of host *)
         * string option (* user name to log in as *)
-        * int option    (* port *)
+        * string option (* port *)
         * string option (* root of replica in host fs *)
   | ConnectBySocket of
           string        (* name of host *)
-        * int           (* port where server should be listening *)
+        * string        (* port where server should be listening *)
         * string option (* root of replica in host fs *)
 
 val clroot2string : clroot -> string
Index: remote.mli
===================================================================
--- remote.mli	(r?vision 92)
+++ remote.mli	(copie de travail)
@@ -36,7 +36,7 @@
 (* Enter "server mode", reading and processing commands from a remote
    client process until killed *)
 val beAServer : unit -> unit
-val waitOnPort : string option -> int -> unit
+val waitOnPort : string option -> string -> unit
 
 (* Whether the server should be killed when the client terminates *)
 val killServer : bool Prefs.t
Index: uigtk.ml
===================================================================
--- uigtk.ml	(r?vision 92)
+++ uigtk.ml	(copie de travail)
@@ -655,21 +655,17 @@
       `Local ->
         Clroot.clroot2string(Clroot.ConnectLocal(Some file))
     | `SSH | `RSH ->
-        let portOpt =
-          (* FIX: report an error if the port entry is not well formed *)
-          try Some(int_of_string(portE#text))
-          with _ -> None in
         Clroot.clroot2string(
         Clroot.ConnectByShell((if !varLocalRemote=`SSH then "ssh" else "rsh"),
                               host,
                               (if user="" then None else Some user),
-                              portOpt,
+                              Some portE#text,
                               Some file))
     | `SOCKET ->
         Clroot.clroot2string(
         (* FIX: report an error if the port entry is not well formed *)
         Clroot.ConnectBySocket(host,
-                               int_of_string(portE#text),
+                               portE#text,
                                Some file)) in
   let contCommand() =
     try
Index: main.ml
===================================================================
--- main.ml	(r?vision 92)
+++ main.ml	(copie de travail)
@@ -183,15 +183,7 @@
 
   (* Start a socket server if requested *)
   begin try
-    let i =
-      match Util.StringMap.find socketPrefName argv with
-        [] ->
-          assert false
-      | i::_ ->
-          try int_of_string i with Failure _ ->
-            Util.msg "-socket must be followed by a number\n";
-            exit 1
-    in
+    let i = List.hd (Util.StringMap.find socketPrefName argv) in
     catch_all (fun () ->
       Os.createUnisonDir();
       Remote.waitOnPort


More information about the Unison-hackers mailing list