On Wed, Nov 02, 2022 at 09:10:02PM +0000, Richard W.M. Jones wrote:
> 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).
The namespacing has actually been fixed upstream ('caml_unix_get_sockaddr').
There is a backwards compatible #define, but I guess we will need to
have some autoconf test to choose the right symbol. I don't have a
version of OCaml that has the namespaced symbol.
Rich.
> 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
>
> _______________________________________________
> Libguestfs mailing list
> [email protected]
> https://listman.redhat.com/mailman/listinfo/libguestfs
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
libguestfs lets you edit virtual machines. Supports shell scripting,
bindings from many languages. http://libguestfs.org
_______________________________________________
Libguestfs mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/libguestfs