Richard W.M. Jones
2019-Oct-04 19:50 UTC
[Libguestfs] [PATCH libnbd 1/4] generator: Allow long ‘name - shortdesc’ in man pages.
For commands with long names and/or short descriptors, you can end up going over 72 characters in the first line of the man page (causing podwrapper to complain). Wrap these lines. --- generator/generator | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generator/generator b/generator/generator index 7d3f656..ad1cb6b 100755 --- a/generator/generator +++ b/generator/generator @@ -4487,7 +4487,8 @@ let generate_docs_nbd_pod name { args; optargs; ret; first_version = (major, minor) } () pr "=head1 NAME\n"; pr "\n"; - pr "nbd_%s - %s\n" name shortdesc; + pr_wrap ' ' (fun () -> pr "nbd_%s - %s" name shortdesc); + pr "\n"; pr "\n"; pr "=head1 SYNOPSIS\n"; -- 2.23.0
Richard W.M. Jones
2019-Oct-04 19:50 UTC
[Libguestfs] [PATCH libnbd 2/4] api: Rename nbd_connect_socket_activation -> nbd_connect_systemd_socket_activation.
While the new name is quite long, the purpose is to prevent confusion with a proposed new API to be called nbd_connect_socket. Note that this API was never in a released stable version of libnbd so we can change it at will during development. --- docs/libnbd.pod | 4 ++-- examples/open-qcow2.c | 3 ++- generator/generator | 14 +++++++------- interop/dirty-bitmap.c | 2 +- interop/interop.c | 2 +- interop/socket-activation.c | 2 +- interop/structured-read.c | 2 +- lib/connect.c | 8 +++++--- 8 files changed, 20 insertions(+), 17 deletions(-) diff --git a/docs/libnbd.pod b/docs/libnbd.pod index dfd8735..ef4c7de 100644 --- a/docs/libnbd.pod +++ b/docs/libnbd.pod @@ -438,8 +438,8 @@ testing. Some NBD servers — notably L<nbdkit(1)> and L<qemu-nbd(1)> — support systemd socket activation allowing libnbd to pass a socket to the subprocess. This works very similarly to L<nbd_connect_command(3)> -described above, but you must use L<nbd_connect_socket_activation(3)> -instead. +described above, but you must use +L<nbd_connect_systemd_socket_activation(3)> instead. =head1 EXPORTS AND FLAGS diff --git a/examples/open-qcow2.c b/examples/open-qcow2.c index 27c0e1f..79572f1 100644 --- a/examples/open-qcow2.c +++ b/examples/open-qcow2.c @@ -37,7 +37,8 @@ main (int argc, char *argv[]) (char *) filename, NULL }; - if (nbd_connect_socket_activation (nbd, args) == -1) { + if (nbd_connect_systemd_socket_activation (nbd, + args) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/generator/generator b/generator/generator index ad1cb6b..c7464d5 100755 --- a/generator/generator +++ b/generator/generator @@ -95,7 +95,7 @@ type external_event | CmdConnectUnix (* [nbd_aio_connect_unix] *) | CmdConnectTCP (* [nbd_aio_connect_tcp] *) | CmdConnectCommand (* [nbd_aio_connect_command] *) - | CmdConnectSA (* [nbd_aio_connect_socket_activation] *) + | CmdConnectSA (* [nbd_aio_connect_systemd_socket_activation]*) | CmdIssue (* issuing an NBD command *) type location = string * int (* source location: file, line number *) @@ -275,7 +275,7 @@ and connect_command_state_machine = [ }; ] -(* State machine implementing [nbd_aio_connect_socket_activation]. *) +(* State machine implementing [nbd_aio_connect_systemd_socket_activation]. *) and connect_sa_state_machine = [ State { default_state with @@ -1528,7 +1528,7 @@ is killed."; example = Some "examples/connect-command.c"; }; - "connect_socket_activation", { + "connect_systemd_socket_activation", { default_call with args = [ StringList "argv" ]; ret = RErr; permitted_states = [ Created ]; @@ -2161,7 +2161,7 @@ and completed the NBD handshake by calling L<nbd_aio_is_ready(3)>, on the connection."; }; - "aio_connect_socket_activation", { + "aio_connect_systemd_socket_activation", { default_call with args = [ StringList "argv" ]; ret = RErr; permitted_states = [ Created ]; @@ -2169,7 +2169,7 @@ on the connection."; longdesc = "\ Run the command as a subprocess and begin connecting to it using systemd socket activation. Parameters behave as documented in -L<nbd_connect_socket_activation(3)>. +L<nbd_connect_systemd_socket_activation(3)>. You can check if the connection is still connecting by calling L<nbd_aio_is_connecting(3)>, or if it has connected to the server @@ -2756,8 +2756,8 @@ let first_version = [ "get_protocol", (1, 2); "set_handshake_flags", (1, 2); "get_handshake_flags", (1, 2); - "connect_socket_activation", (1, 2); - "aio_connect_socket_activation", (1, 2); + "connect_systemd_socket_activation", (1, 2); + "aio_connect_systemd_socket_activation", (1, 2); (* These calls are proposed for a future version of libnbd, but * have not been added to any released version so far. diff --git a/interop/dirty-bitmap.c b/interop/dirty-bitmap.c index a300388..5f9fa12 100644 --- a/interop/dirty-bitmap.c +++ b/interop/dirty-bitmap.c @@ -123,7 +123,7 @@ main (int argc, char *argv[]) nbd_add_meta_context (nbd, LIBNBD_CONTEXT_BASE_ALLOCATION); nbd_add_meta_context (nbd, bitmap); - if (nbd_connect_socket_activation (nbd, &argv[2]) == -1) { + if (nbd_connect_systemd_socket_activation (nbd, &argv[2]) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/interop/interop.c b/interop/interop.c index c0140a0..5428544 100644 --- a/interop/interop.c +++ b/interop/interop.c @@ -100,7 +100,7 @@ main (int argc, char *argv[]) /* Start the server. */ #if SOCKET_ACTIVATION -#define NBD_CONNECT nbd_connect_socket_activation +#define NBD_CONNECT nbd_connect_systemd_socket_activation #else #define NBD_CONNECT nbd_connect_command #endif diff --git a/interop/socket-activation.c b/interop/socket-activation.c index db6f6ca..8fe2cfa 100644 --- a/interop/socket-activation.c +++ b/interop/socket-activation.c @@ -56,7 +56,7 @@ main (int argc, char *argv[]) } char *args[] = { SERVER, SERVER_PARAMS, NULL }; - if (nbd_connect_socket_activation (nbd, args) == -1) { + if (nbd_connect_systemd_socket_activation (nbd, args) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); goto out; } diff --git a/interop/structured-read.c b/interop/structured-read.c index 6e85b65..13ec4f2 100644 --- a/interop/structured-read.c +++ b/interop/structured-read.c @@ -119,7 +119,7 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } - if (nbd_connect_socket_activation (nbd, &argv[1]) == -1) { + if (nbd_connect_systemd_socket_activation (nbd, &argv[1]) == -1) { fprintf (stderr, "%s\n", nbd_get_error ()); exit (EXIT_FAILURE); } diff --git a/lib/connect.c b/lib/connect.c index c1cbef7..d648dd3 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -114,9 +114,10 @@ nbd_unlocked_connect_command (struct nbd_handle *h, char **argv) /* Connect to a local command, use systemd socket activation. */ int -nbd_unlocked_connect_socket_activation (struct nbd_handle *h, char **argv) +nbd_unlocked_connect_systemd_socket_activation (struct nbd_handle *h, + char **argv) { - if (nbd_unlocked_aio_connect_socket_activation (h, argv) == -1) + if (nbd_unlocked_aio_connect_systemd_socket_activation (h, argv) == -1) return -1; return wait_until_connected (h); @@ -417,7 +418,8 @@ nbd_unlocked_aio_connect_command (struct nbd_handle *h, char **argv) } int -nbd_unlocked_aio_connect_socket_activation (struct nbd_handle *h, char **argv) +nbd_unlocked_aio_connect_systemd_socket_activation (struct nbd_handle *h, + char **argv) { char **copy; -- 2.23.0
Richard W.M. Jones
2019-Oct-04 19:50 UTC
[Libguestfs] [PATCH libnbd 3/4] api: Add nbd_connect_socket.
This allows us to connect directly to a connected socket. How exactly the socket is created and connected to the NBD server is left up to the main program. The only real complexity in this patch is allowing file descriptors to be passed to libnbd APIs. Luckily in C and Python we can treat them exactly as integers, and in OCaml they are also integers but with a different type. --- generator/generator | 72 ++++++++++++++++++++++++++++++++++++--------- lib/connect.c | 47 +++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 14 deletions(-) diff --git a/generator/generator b/generator/generator index c7464d5..54a8eb7 100755 --- a/generator/generator +++ b/generator/generator @@ -96,6 +96,7 @@ type external_event | CmdConnectTCP (* [nbd_aio_connect_tcp] *) | CmdConnectCommand (* [nbd_aio_connect_command] *) | CmdConnectSA (* [nbd_aio_connect_systemd_socket_activation]*) + | CmdConnectSocket (* [nbd_aio_connect_socket] *) | CmdIssue (* issuing an NBD command *) type location = string * int (* source location: file, line number *) @@ -170,7 +171,8 @@ let rec state_machine = [ CmdConnectUnix, "CONNECT_UNIX.START"; CmdConnectTCP, "CONNECT_TCP.START"; CmdConnectCommand, "CONNECT_COMMAND.START"; - CmdConnectSA, "CONNECT_SA.START" ]; + CmdConnectSA, "CONNECT_SA.START"; + CmdConnectSocket, "MAGIC.START" ]; }; Group ("CONNECT", connect_state_machine); @@ -883,6 +885,7 @@ and arg | BytesPersistOut of string * string | Closure of closure (* function pointer + void *opaque *) | Enum of string * enum (* enum/union type, int in C *) +| Fd of string (* file descriptor *) | Flags of string * flags (* flags, uint32_t in C *) | Int of string (* small int *) | Int64 of string (* 64 bit signed int *) @@ -1501,6 +1504,21 @@ such as C<\"10809\">. This call returns when the connection has been made."; }; + "connect_socket", { + default_call with + args = [ Fd "sock" ]; ret = RErr; + permitted_states = [ Created ]; + shortdesc = "connect directly to a connected socket"; + longdesc = "\ +Pass a connected socket (file descriptor) which libnbd will +talk to. The program is responsible for connecting this +somehow to an NBD server. Once the socket is passed to +libnbd it is the responsibility of libnbd. Libnbd may +read and write to it, set it to non-blocking, etc., and +will finally close it when the handle is closed. The +program must no longer use the socket."; + }; + "connect_command", { default_call with args = [ StringList "argv" ]; ret = RErr; @@ -2139,6 +2157,21 @@ on the connection."; Begin connecting to the NBD server listening on C<hostname:port>. Parameters behave as documented in L<nbd_connect_tcp(3)>. +You can check if the connection is still connecting by calling +L<nbd_aio_is_connecting(3)>, or if it has connected to the server +and completed the NBD handshake by calling L<nbd_aio_is_ready(3)>, +on the connection."; + }; + + "aio_connect_socket", { + default_call with + args = [ Fd "sock" ]; ret = RErr; + permitted_states = [ Created ]; + shortdesc = "connect directly to a connected socket"; + longdesc = "\ +Begin connecting to the connected socket C<fd>. +Parameters behave as documented in L<nbd_connect_socket(3)>. + You can check if the connection is still connecting by calling L<nbd_aio_is_connecting(3)>, or if it has connected to the server and completed the NBD handshake by calling L<nbd_aio_is_ready(3)>, @@ -2758,6 +2791,8 @@ let first_version = [ "get_handshake_flags", (1, 2); "connect_systemd_socket_activation", (1, 2); "aio_connect_systemd_socket_activation", (1, 2); + "connect_socket", (1, 2); + "aio_connect_socket", (1, 2); (* These calls are proposed for a future version of libnbd, but * have not been added to any released version so far. @@ -3117,7 +3152,7 @@ let all_external_events [NotifyRead; NotifyWrite; CmdCreate; CmdConnectSockAddr; CmdConnectUnix; CmdConnectTCP; - CmdConnectCommand; CmdConnectSA; + CmdConnectCommand; CmdConnectSA; CmdConnectSocket; CmdIssue] let string_of_external_event = function @@ -3129,6 +3164,7 @@ let string_of_external_event = function | CmdConnectTCP -> "CmdConnectTCP" | CmdConnectCommand -> "CmdConnectCommand" | CmdConnectSA -> "CmdConnectSA" + | CmdConnectSocket -> "CmdConnectSocket" | CmdIssue -> "CmdIssue" let c_string_of_external_event = function @@ -3140,6 +3176,7 @@ let c_string_of_external_event = function | CmdConnectTCP -> "cmd_connect_tcp" | CmdConnectCommand -> "cmd_connect_command" | CmdConnectSA -> "cmd_connect_sa" + | CmdConnectSocket -> "cmd_connect_socket" | CmdIssue -> "cmd_issue" (* Find a state in the state machine hierarchy by path. The [path] @@ -3588,7 +3625,7 @@ let generate_lib_states_run_c () | CmdCreate | CmdConnectSockAddr | CmdConnectUnix | CmdConnectTCP - | CmdConnectCommand | CmdConnectSA + | CmdConnectCommand | CmdConnectSA | CmdConnectSocket | CmdIssue -> () ) events; pr " break;\n"; @@ -3870,6 +3907,7 @@ let rec name_of_arg = function | Closure { cbname } -> [ sprintf "%s_callback" cbname; sprintf "%s_user_data" cbname ] | Enum (n, _) -> [n] +| Fd n -> [n] | Flags (n, _) -> [n] | Int n -> [n] | Int64 n -> [n] @@ -3926,7 +3964,7 @@ and print_arg_list_no_parens ?(handle = false) ?(types = true) args optargs | Flags (n, _) -> if types then pr "uint32_t "; pr "%s" n - | Int n -> + | Fd n | Int n -> if types then pr "int "; pr "%s" n | Int64 n -> @@ -4350,7 +4388,7 @@ let generate_lib_api_c () | Closure { cbname } -> pr " %s=<fun>" cbname | Enum (n, _) -> pr " %s=%%d" n | Flags (n, _) -> pr " %s=0x%%x" n - | Int n -> pr " %s=%%d" n + | Fd n | Int n -> pr " %s=%%d" n | Int64 n -> pr " %s=%%\" PRIi64 \"" n | SockAddrAndLen (n, len) -> pr " %s=<sockaddr> %s=%%d" n len | Path n @@ -4376,7 +4414,7 @@ let generate_lib_api_c () | Closure { cbname } -> () | Enum (n, _) -> pr ", %s" n | Flags (n, _) -> pr ", %s" n - | Int n -> pr ", %s" n + | Fd n | Int n -> pr ", %s" n | Int64 n -> pr ", %s" n | SockAddrAndLen (_, len) -> pr ", (int) %s" len | Path n | String n -> pr ", %s ? %s : \"NULL\"" n n @@ -4889,7 +4927,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } | Flags (n, _) -> pr " uint32_t %s_u32;\n" n; pr " unsigned int %s; /* really uint32_t */\n" n - | Int n -> pr " int %s;\n" n + | Fd n | Int n -> pr " int %s;\n" n | Int64 n -> pr " int64_t %s_i64;\n" n; pr " long long %s; /* really int64_t */\n" n @@ -4940,7 +4978,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } | Closure _ -> pr " \"O\"" | Enum _ -> pr " \"i\"" | Flags _ -> pr " \"I\"" - | Int n -> pr " \"i\"" + | Fd n | Int n -> pr " \"i\"" | Int64 n -> pr " \"L\"" | Path n -> pr " \"O&\"" | SockAddrAndLen (n, _) -> pr " \"O\"" @@ -4967,7 +5005,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } | Closure { cbname } -> pr ", &%s_user_data->fn" cbname | Enum (n, _) -> pr ", &%s" n | Flags (n, _) -> pr ", &%s" n - | Int n -> pr ", &%s" n + | Fd n | Int n -> pr ", &%s" n | Int64 n -> pr ", &%s" n | Path n -> pr ", PyUnicode_FSConverter, &py_%s" n | SockAddrAndLen (n, _) -> pr ", &%s" n @@ -5004,7 +5042,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } pr " }\n" | Enum _ -> () | Flags (n, _) -> pr " %s_u32 = %s;\n" n n - | Int _ -> () + | Fd _ | Int _ -> () | Int64 n -> pr " %s_i64 = %s;\n" n n | Path n -> pr " %s = PyBytes_AS_STRING (py_%s);\n" n n; @@ -5062,7 +5100,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } | Closure { cbname } -> pr ", %s" cbname | Enum (n, _) -> pr ", %s" n | Flags (n, _) -> pr ", %s_u32" n - | Int n -> pr ", %s" n + | Fd n | Int n -> pr ", %s" n | Int64 n -> pr ", %s_i64" n | Path n -> pr ", %s" n | SockAddrAndLen (n, _) -> pr ", /* XXX */ (void *) %s, 0" n @@ -5100,7 +5138,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } | Closure _ | Enum _ | Flags _ - | Int _ + | Fd _ | Int _ | Int64 _ | Path _ | SockAddrAndLen _ @@ -5142,7 +5180,7 @@ let print_python_binding name { args; optargs; ret; may_set_error } | Closure _ -> () | Enum _ -> () | Flags _ -> () - | Int _ -> () + | Fd _ | Int _ -> () | Int64 _ -> () | Path n -> pr " Py_XDECREF (py_%s);\n" n @@ -5351,7 +5389,7 @@ class NBD (object): | Closure { cbname } -> cbname, None, None | Enum (n, _) -> n, None, None | Flags (n, _) -> n, None, None - | Int n -> n, None, None + | Fd n | Int n -> n, None, None | Int64 n -> n, None, None | Path n -> n, None, None | SockAddrAndLen (n, _) -> n, None, None @@ -5431,6 +5469,7 @@ and ocaml_arg_to_string = function | Closure { cbargs } -> sprintf "(%s)" (ocaml_closuredecl_to_string cbargs) | Enum (_, { enum_prefix }) -> sprintf "%s.t" enum_prefix + | Fd _ -> "Unix.file_descr" | Flags (_, { flag_prefix }) -> sprintf "%s.t" flag_prefix | Int _ -> "int" | Int64 _ -> "int64" @@ -5482,6 +5521,7 @@ let ocaml_name_of_arg = function | BytesPersistOut (n, len) -> n | Closure { cbname } -> cbname | Enum (n, _) -> n + | Fd n -> n | Flags (n, _) -> n | Int n -> n | Int64 n -> n @@ -5945,6 +5985,9 @@ let print_ocaml_binding (name, { args; optargs; ret }) pr " %s_callback.free = free_user_data;\n" cbname | Enum (n, { enum_prefix }) -> pr " int %s = %s_val (%sv);\n" n enum_prefix n + | Fd n -> + pr " /* OCaml Unix.file_descr is just an int, at least on Unix. */\n"; + pr " int %s = Int_val (%sv);\n" n n | Flags (n, { flag_prefix }) -> pr " uint32_t %s = %s_val (%sv);\n" n flag_prefix n | Int n -> @@ -6018,6 +6061,7 @@ let print_ocaml_binding (name, { args; optargs; ret }) | BytesPersistOut _ | Closure _ | Enum _ + | Fd _ | Flags _ | Int _ | Int64 _ diff --git a/lib/connect.c b/lib/connect.c index d648dd3..a0ef5f1 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -23,6 +23,7 @@ #include <stdbool.h> #include <errno.h> #include <unistd.h> +#include <fcntl.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> @@ -102,6 +103,16 @@ nbd_unlocked_connect_tcp (struct nbd_handle *h, return wait_until_connected (h); } +/* Connect to a connected socket. */ +int +nbd_unlocked_connect_socket (struct nbd_handle *h, int sock) +{ + if (nbd_unlocked_aio_connect_socket (h, sock) == -1) + return -1; + + return wait_until_connected (h); +} + /* Connect to a local command. */ int nbd_unlocked_connect_command (struct nbd_handle *h, char **argv) @@ -399,6 +410,42 @@ nbd_unlocked_aio_connect_tcp (struct nbd_handle *h, return nbd_internal_run (h, cmd_connect_tcp); } +int +nbd_unlocked_aio_connect_socket (struct nbd_handle *h, int sock) +{ + int flags; + + /* Set O_NONBLOCK on the file and FD_CLOEXEC on the file descriptor. + * We can't trust that the calling process did either of these. + */ + flags = fcntl (sock, F_GETFL, 0); + if (flags == -1 || + fcntl (sock, F_SETFL, flags|O_NONBLOCK) == -1) { + set_error (errno, "fcntl: set O_NONBLOCK"); + close (sock); + return -1; + } + + flags = fcntl (sock, F_GETFD, 0); + if (flags == -1 || + fcntl (sock, F_SETFD, flags|FD_CLOEXEC) == -1) { + set_error (errno, "fcntl: set FD_CLOEXEC"); + close (sock); + return -1; + } + + h->sock = nbd_internal_socket_create (sock); + if (!h->sock) { + close (sock); + return -1; + } + + /* This jumps straight to %MAGIC.START (to start the handshake) + * because the socket is already connected. + */ + return nbd_internal_run (h, cmd_connect_socket); +} + int nbd_unlocked_aio_connect_command (struct nbd_handle *h, char **argv) { -- 2.23.0
Richard W.M. Jones
2019-Oct-04 19:50 UTC
[Libguestfs] [PATCH libnbd 4/4] fuzzing: Use the new nbd_connect_socket API.
Simplifies the code and avoids having a Unix domain socket on disk. --- fuzzing/libnbd-fuzz-wrapper.c | 78 ++++++++++------------------------- 1 file changed, 21 insertions(+), 57 deletions(-) diff --git a/fuzzing/libnbd-fuzz-wrapper.c b/fuzzing/libnbd-fuzz-wrapper.c index ba3840a..bfaa072 100644 --- a/fuzzing/libnbd-fuzz-wrapper.c +++ b/fuzzing/libnbd-fuzz-wrapper.c @@ -35,22 +35,18 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> -#include <sys/un.h> #include <libnbd.h> -static void client (const char *sockpath); +static void client (int s); static void server (int fd, int s); int main (int argc, char *argv[]) { int fd; - char tmpdir[] = "/tmp/sockXXXXXX"; - char *sockpath; - struct sockaddr_un addr; pid_t pid; - int s, r, status; + int sv[2], r, status; if (argc != 2) { fprintf (stderr, "libnbd-fuzz-wrapper testcase\n"); @@ -64,29 +60,9 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); } - /* Create a randomly named Unix domain socket. */ - if (mkdtemp (tmpdir) == NULL) { - perror ("mkdtemp"); - exit (EXIT_FAILURE); - } - if (asprintf (&sockpath, "%s/sock", tmpdir) == -1) { - perror ("asprintf"); - exit (EXIT_FAILURE); - } - - s = socket (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); - if (s == -1) { - perror ("socket"); - exit (EXIT_FAILURE); - } - addr.sun_family = AF_UNIX; - memcpy (addr.sun_path, sockpath, strlen (sockpath) + 1); - if (bind (s, (struct sockaddr *) &addr, sizeof addr) == -1) { - perror (sockpath); - exit (EXIT_FAILURE); - } - if (listen (s, 1) == -1) { - perror ("listen"); + /* Create a connected socket. */ + if (socketpair (AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sv) == -1) { + perror ("socketpair"); exit (EXIT_FAILURE); } @@ -101,9 +77,12 @@ main (int argc, char *argv[]) if (pid > 0) { /* Parent: libnbd client. */ - close (s); + close (sv[1]); close (fd); - client (sockpath); + + client (sv[0]); + + close (sv[0]); r = wait (&status); if (r == -1) { @@ -117,19 +96,17 @@ main (int argc, char *argv[]) } /* Child: phony NBD server. */ - server (fd, s); + close (sv[0]); + + server (fd, sv[1]); - /* Clean up the socket and directory. */ - close (s); - close (fd); - unlink (sockpath); - rmdir (tmpdir); + close (sv[1]); _exit (EXIT_SUCCESS); } static void -client (const char *sockpath) +client (int sock) { struct nbd_handle *nbd; char buf[512]; @@ -144,7 +121,7 @@ client (const char *sockpath) * interested in whether the process crashes. */ /* This tests the handshake phase. */ - nbd_connect_unix (nbd, sockpath); + nbd_connect_socket (nbd, sock); /* XXX We should do some more complicated operations here, * eg exercising structured reads. @@ -155,28 +132,15 @@ client (const char *sockpath) } static void -server (int fd, int listen_sock) +server (int fd, int sock) { - int s; struct pollfd pfds[1]; char rbuf[512], wbuf[512]; size_t wsize = 0; ssize_t r; - int flags; - - /* Accept a single connection on the socket. */ - s = accept (listen_sock, NULL, NULL); - if (s == -1) { - perror ("accept"); - _exit (EXIT_FAILURE); - } - - /* Set the accepted socket to non-blocking mode. */ - flags = fcntl (s, F_GETFL, 0); - if (flags >= 0) fcntl (s, F_SETFL, flags|O_NONBLOCK); for (;;) { - pfds[0].fd = s; + pfds[0].fd = sock; pfds[0].events = POLLIN; if (wsize >= 0 || fd >= 0) pfds[0].events |= POLLOUT; pfds[0].revents = 0; @@ -191,7 +155,7 @@ server (int fd, int listen_sock) /* We can read from the client socket. Just throw away anything sent. */ if ((pfds[0].revents & POLLIN) != 0) { - r = read (s, rbuf, sizeof rbuf); + r = read (sock, rbuf, sizeof rbuf); if (r == -1 && errno != EINTR) { perror ("read"); return; @@ -205,7 +169,7 @@ server (int fd, int listen_sock) /* Write more data from the wbuf. */ if (wsize > 0) { morewrite: - r = write (s, wbuf, wsize); + r = write (sock, wbuf, wsize); if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { perror ("write"); return; @@ -224,7 +188,7 @@ server (int fd, int listen_sock) } else if (r == 0) { fd = -1; /* ignore the file from now on */ - shutdown (s, SHUT_WR); + shutdown (sock, SHUT_WR); } else { wsize = r; -- 2.23.0
Eric Blake
2019-Oct-04 20:08 UTC
Re: [Libguestfs] [PATCH libnbd 3/4] api: Add nbd_connect_socket.
On 10/4/19 2:50 PM, Richard W.M. Jones wrote:> This allows us to connect directly to a connected socket. How exactly > the socket is created and connected to the NBD server is left up to > the main program. > > The only real complexity in this patch is allowing file descriptors to > be passed to libnbd APIs. Luckily in C and Python we can treat them > exactly as integers, and in OCaml they are also integers but with a > different type. > --- > generator/generator | 72 ++++++++++++++++++++++++++++++++++++--------- > lib/connect.c | 47 +++++++++++++++++++++++++++++ > 2 files changed, 105 insertions(+), 14 deletions(-) >> + "connect_socket", { > + default_call with > + args = [ Fd "sock" ]; ret = RErr; > + permitted_states = [ Created ]; > + shortdesc = "connect directly to a connected socket"; > + longdesc = "\ > +Pass a connected socket (file descriptor) which libnbd will > +talk to. The program is responsible for connecting this > +somehow to an NBD server. Once the socket is passed to > +libnbd it is the responsibility of libnbd. Libnbd may > +read and write to it, set it to non-blocking, etc., and > +will finally close it when the handle is closed. The > +program must no longer use the socket."; > + };Do we want a mode where we can hand a socket to libnbd that has already completed handshake phase and is immediately ready for transaction phase? I've seen posts describing alternative programs that do their own handshake before using ioctls to hand an open socket to the kernel kvm module, which only needs to know the size and flags associated with the socket, to proceed to use it without further negotiation. Having such a mode would allow libnbd instead of the kernel ioctl to be used in the same manner. But having that as a separate API rather than trying to cram it into this one is fine. (And same counterpart question for nbdkit: do we want a mode where nbdkit can be handed an already-open socket and details about what flags the client side has been told, and skip handshake straight into serving client transaction requests) Series looks great to me. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
Reasonably Related Threads
- [PATCH libnbd 1/2] lib: Avoid killing subprocess twice.
- [PATCH libnbd v2 0/2] Implement systemd socket activation.
- [PATCH libnbd 0/2] api: Add support for AF_VSOCK.
- [PATCH libnbd 3/4] api: Add nbd_connect_socket.
- [PATCH libnbd 2/2] api: Implement local command with systemd socket activation.