[Libguestfs] [PATCH libnbd] ocaml: Implement sockaddr type

Richard W.M. Jones rjones at redhat.com
Wed Nov 2 21:10:02 UTC 2022


Convert Unix.sockaddr to struct sockaddr.  OCaml provides a function
to do this ('get_sockaddr' - not namespaced!)  This function was
present at least as far back as RHEL 7 (OCaml 4.05).

This also adds a simple test.
---
 generator/OCaml.ml                  |  8 ++--
 ocaml/helpers.c                     | 23 ++++++++++
 ocaml/nbd-c.h                       |  3 ++
 ocaml/tests/Makefile.am             |  1 +
 ocaml/tests/test_580_aio_connect.ml | 67 +++++++++++++++++++++++++++++
 5 files changed, 99 insertions(+), 3 deletions(-)

diff --git a/generator/OCaml.ml b/generator/OCaml.ml
index 8711eab57c..6a280b6734 100644
--- a/generator/OCaml.ml
+++ b/generator/OCaml.ml
@@ -49,7 +49,7 @@ and
   | Int _ -> "int"
   | Int64 _ -> "int64"
   | Path _ -> "string"
-  | SockAddrAndLen _ -> "string" (* XXX not impl *)
+  | SockAddrAndLen _ -> "Unix.sockaddr"
   | SizeT _ -> "int" (* OCaml int type is always sufficient for counting *)
   | String _ -> "string"
   | StringList _ -> "string list"
@@ -702,9 +702,11 @@ let
     | SizeT n ->
        pr "  size_t %s = Int_val (%sv);\n" n n
     | SockAddrAndLen (n, len) ->
-       pr "  const struct sockaddr *%s;\n" n;
+       pr "  struct sockaddr_storage %s_storage;\n" n;
+       pr "  struct sockaddr *%s = (struct sockaddr *) &%s_storage;\n" n n;
        pr "  socklen_t %s;\n" len;
-       pr "  abort ();\n" (* XXX *)
+       pr "  nbd_internal_unix_sockaddr_to_sa (%sv, &%s_storage, &%s);\n"
+         n n len
     | StringList n ->
        pr "  char **%s = (char **) nbd_internal_ocaml_string_list (%sv);\n" n n
     | UInt n | UIntPtr n ->
diff --git a/ocaml/helpers.c b/ocaml/helpers.c
index aafb970ff9..2981135647 100644
--- a/ocaml/helpers.c
+++ b/ocaml/helpers.c
@@ -23,6 +23,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/socket.h>
+#include <assert.h>
 
 #include <caml/alloc.h>
 #include <caml/callback.h>
@@ -30,6 +32,7 @@
 #include <caml/memory.h>
 #include <caml/mlvalues.h>
 #include <caml/printexc.h>
+#include <caml/socketaddr.h>
 #include <caml/unixsupport.h>
 
 #include <libnbd.h>
@@ -130,6 +133,26 @@ nbd_internal_ocaml_alloc_int64_from_uint32_array (uint32_t *a, size_t len)
   CAMLreturn (rv);
 }
 
+/* Convert a Unix.sockaddr to a C struct sockaddr. */
+void
+nbd_internal_unix_sockaddr_to_sa (value sockaddrv,
+                                  struct sockaddr_storage *ss,
+                                  socklen_t *len)
+{
+  CAMLparam1 (sockaddrv);
+  union sock_addr_union sa_u;
+  socklen_param_type sl; /* this is really an int or socklen_t */
+
+  memset (ss, 0, sizeof *ss);
+
+  get_sockaddr (sockaddrv, &sa_u, &sl);
+  assert (sl <= sizeof *ss);
+  memcpy (ss, &sa_u, sl);
+  *len = sl;
+
+  CAMLreturn0;
+}
+
 /* Common code when an exception is raised in an OCaml callback.
  *
  * We handle Assert_failure specially by abort()-ing.  Other
diff --git a/ocaml/nbd-c.h b/ocaml/nbd-c.h
index 0bf044ca91..8b0c088da7 100644
--- a/ocaml/nbd-c.h
+++ b/ocaml/nbd-c.h
@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include <string.h>
+#include <sys/socket.h>
 
 #include <caml/alloc.h>
 #include <caml/custom.h>
@@ -62,6 +63,8 @@ extern void nbd_internal_ocaml_raise_closed (const char *func) Noreturn;
 extern const char **nbd_internal_ocaml_string_list (value);
 extern value nbd_internal_ocaml_alloc_int64_from_uint32_array (uint32_t *,
                                                                size_t);
+extern void nbd_internal_unix_sockaddr_to_sa (value, struct sockaddr_storage *,
+                                              socklen_t *);
 extern void nbd_internal_ocaml_exception_in_wrapper (const char *, value);
 
 /* Extract an NBD handle from an OCaml heap value. */
diff --git a/ocaml/tests/Makefile.am b/ocaml/tests/Makefile.am
index 328d53e543..2cd36eb067 100644
--- a/ocaml/tests/Makefile.am
+++ b/ocaml/tests/Makefile.am
@@ -42,6 +42,7 @@ ML_TESTS = \
 	test_500_aio_pread.ml \
 	test_505_aio_pread_structured_callback.ml \
 	test_510_aio_pwrite.ml \
+	test_580_aio_connect.ml \
 	test_590_aio_copy.ml \
 	test_600_debug_callback.ml \
 	test_610_exception.ml \
diff --git a/ocaml/tests/test_580_aio_connect.ml b/ocaml/tests/test_580_aio_connect.ml
new file mode 100644
index 0000000000..95acc18c10
--- /dev/null
+++ b/ocaml/tests/test_580_aio_connect.ml
@@ -0,0 +1,67 @@
+(* hey emacs, this is OCaml code: -*- tuareg -*- *)
+(* libnbd OCaml test case
+ * Copyright (C) 2013-2022 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *)
+
+open Unix
+open Printf
+
+let () =
+  let nbd = NBD.create () in
+
+  (* Unlike other tests, we're going to run nbdkit as a subprocess
+   * by hand and have it listening on a randomly named socket
+   * that we create.
+   *)
+  let sock = Filename.temp_file "580-" ".sock" in
+  unlink sock;
+  let pidfile = Filename.temp_file "580-" ".pid" in
+  unlink pidfile;
+  let cmd =
+    sprintf "nbdkit -U %s -P %s --exit-with-parent memory size=512 &"
+      (Filename.quote sock) (Filename.quote pidfile) in
+  if Sys.command cmd <> 0 then
+    failwith "nbdkit command failed";
+  let rec loop i =
+    if i > 60 then
+      failwith "nbdkit subcommand did not start up";
+    if not (Sys.file_exists pidfile) then (
+      sleep 1;
+      loop (i+1)
+    )
+  in
+  loop 0;
+
+  (* Connect to the subprocess using a Unix.sockaddr. *)
+  let sa = ADDR_UNIX sock in
+  NBD.aio_connect nbd sa;
+  while NBD.aio_is_connecting nbd do
+    ignore (NBD.poll nbd 1)
+  done;
+  assert (NBD.aio_is_ready nbd);
+  NBD.close nbd;
+
+  (* Kill the nbdkit subprocess. *)
+  let chan = open_in pidfile in
+  let pid = int_of_string (input_line chan) in
+  kill pid Sys.sigint;
+
+  (* Clean up files. *)
+  unlink sock;
+  unlink pidfile
+
+let () = Gc.compact ()
-- 
2.37.0.rc2



More information about the Libguestfs mailing list