This commit adds a new API which can be used from the connected to
state to read back which NBD protocol (eg. oldstyle, newstyle-fixed)
we are using.
It was helpful to add a new state in newstyle negotiation
(%NEWSTYLE.FINISHED) so we can route all successful option
negotiations through a single path before moving to the %READY state,
allowing us to set h->protocol in one place.
---
generator/generator | 25 +++++++++++++++++++++
generator/states-newstyle-opt-export-name.c | 2 +-
generator/states-newstyle-opt-go.c | 2 +-
generator/states-newstyle.c | 9 ++++++++
generator/states-oldstyle.c | 2 ++
lib/handle.c | 12 ++++++++++
lib/internal.h | 5 ++++-
tests/get-size.c | 13 ++++++++++-
tests/oldstyle.c | 9 ++++++++
9 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/generator/generator b/generator/generator
index 28248ed..21aae3b 100755
--- a/generator/generator
+++ b/generator/generator
@@ -357,6 +357,16 @@ and newstyle_state_machine = [
Group ("OPT_SET_META_CONTEXT", newstyle_opt_set_meta_context_state_machine);
Group ("OPT_GO", newstyle_opt_go_state_machine);
Group ("OPT_EXPORT_NAME", newstyle_opt_export_name_state_machine);
+
+ (* When option parsing has successfully finished negotiation
+ * it will jump to this state for final steps before moving to
+ * the %READY state.
+ *)
+ State {
+ default_state with
+ name = "FINISHED";
+ comment = "Finish off newstyle negotiation";
+ };
]
(* Fixed newstyle NBD_OPT_STARTTLS option. *)
@@ -1574,6 +1584,20 @@ are free to pass in other contexts."
"L<nbd_block_status(3)>";
"L<nbd_aio_block_status(3)>"];
};
+ "get_protocol", {
+ default_call with
+ args = []; ret = RStaticString;
+ permitted_states = [ Connected; Closed ];
+ shortdesc = "return the NBD protocol variant";
+ longdesc = "\
+Return the NBD protocol variant in use on the connection. At
+the moment this returns one of the strings C<\"oldstyle\">,
+C<\"newstyle\"> or C<\"newstyle-fixed\">. Other strings
might
+be returned in future. Most modern NBD servers use
C<\"newstyle-fixed\">.
+"
+^ non_blocking_test_call_description
+ };
+
"get_size", {
default_call with
args = []; ret = RInt64;
@@ -2553,6 +2577,7 @@ let first_version = [
"set_request_structured_replies", (1, 2);
"get_request_structured_replies", (1, 2);
"get_tls_negotiated", (1, 2);
+ "get_protocol", (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/generator/states-newstyle-opt-export-name.c
b/generator/states-newstyle-opt-export-name.c
index ec73136..1c6b443 100644
--- a/generator/states-newstyle-opt-export-name.c
+++ b/generator/states-newstyle-opt-export-name.c
@@ -68,7 +68,7 @@
SET_NEXT_STATE (%.DEAD);
return 0;
}
- SET_NEXT_STATE (%.READY);
+ SET_NEXT_STATE (%^FINISHED);
return 0;
} /* END STATE MACHINE */
diff --git a/generator/states-newstyle-opt-go.c b/generator/states-newstyle-opt-go.c
index 49875a5..d0d2123 100644
--- a/generator/states-newstyle-opt-go.c
+++ b/generator/states-newstyle-opt-go.c
@@ -108,7 +108,7 @@
switch (reply) {
case NBD_REP_ACK:
- SET_NEXT_STATE (%.READY);
+ SET_NEXT_STATE (%^FINISHED);
return 0;
case NBD_REP_INFO:
if (len > maxpayload /* see RECV_NEWSTYLE_OPT_GO_REPLY */)
diff --git a/generator/states-newstyle.c b/generator/states-newstyle.c
index c8f817e..7742ea3 100644
--- a/generator/states-newstyle.c
+++ b/generator/states-newstyle.c
@@ -155,4 +155,13 @@ handle_reply_error (struct nbd_handle *h)
}
return 0;
+ NEWSTYLE.FINISHED:
+ if ((h->gflags & NBD_FLAG_FIXED_NEWSTYLE) == 0)
+ h->protocol = "newstyle";
+ else
+ h->protocol = "newstyle-fixed";
+
+ SET_NEXT_STATE (%.READY);
+ return 0;
+
} /* END STATE MACHINE */
diff --git a/generator/states-oldstyle.c b/generator/states-oldstyle.c
index 1aff185..cb4f0da 100644
--- a/generator/states-oldstyle.c
+++ b/generator/states-oldstyle.c
@@ -64,6 +64,8 @@
return 0;
}
+ h->protocol = "oldstyle";
+
SET_NEXT_STATE (%.READY);
return 0;
diff --git a/lib/handle.c b/lib/handle.c
index bc4206c..85d10cd 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -315,3 +315,15 @@ nbd_unlocked_supports_uri (struct nbd_handle *h)
return 0;
#endif
}
+
+const char *
+nbd_unlocked_get_protocol (struct nbd_handle *h)
+{
+ /* I believe that if we reach the Connected or Closed permitted
+ * states, then the state machine must have set h->protocol. So if
+ * this assertion is hit then it indicates a bug in libnbd.
+ */
+ assert (h->protocol);
+
+ return h->protocol;
+}
diff --git a/lib/internal.h b/lib/internal.h
index eb76ac1..87b413d 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -87,7 +87,10 @@ struct nbd_handle {
uint64_t exportsize;
uint16_t eflags;
- /* Flag set by the state machine to tell whether TLS was negotiated. */
+ /* Flags set by the state machine to tell what protocol and whether
+ * TLS was negotiated.
+ */
+ const char *protocol;
bool tls_negotiated;
int64_t unique; /* Used for generating cookie numbers. */
diff --git a/tests/get-size.c b/tests/get-size.c
index f10597c..e6f44f7 100644
--- a/tests/get-size.c
+++ b/tests/get-size.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
+#include <string.h>
#include <libnbd.h>
@@ -38,8 +39,10 @@ main (int argc, char *argv[])
{
struct nbd_handle *nbd;
int64_t r;
- char *args[] = { "nbdkit", "-s", "--exit-with-parent",
"-v",
+ /* -n forces newstyle even if someone is still using nbdkit < 1.3 */
+ char *args[] = { "nbdkit", "-s", "--exit-with-parent",
"-n", "-v",
"null", "size=" STR(SIZE), NULL };
+ const char *s;
nbd = nbd_create ();
if (nbd == NULL) {
@@ -51,6 +54,14 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
+ /* Even ancient versions of nbdkit only supported newstyle-fixed. */
+ s = nbd_get_protocol (nbd);
+ if (strcmp (s, "newstyle-fixed") != 0) {
+ fprintf (stderr,
+ "incorrect protocol \"%s\", expected
\"newstyle-fixed\"\n", s);
+ exit (EXIT_FAILURE);
+ }
+
if ((r = nbd_get_size (nbd)) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
diff --git a/tests/oldstyle.c b/tests/oldstyle.c
index c179c45..b90b775 100644
--- a/tests/oldstyle.c
+++ b/tests/oldstyle.c
@@ -84,6 +84,7 @@ main (int argc, char *argv[])
char *args[] = { "nbdkit", "-s", "-o",
"--exit-with-parent", "-v",
"memory", "size=" STR(SIZE), NULL };
int calls = 0;
+ const char *s;
progname = argv[0];
@@ -114,6 +115,14 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE);
}
+ /* Protocol should be "oldstyle". */
+ s = nbd_get_protocol (nbd);
+ if (strcmp (s, "oldstyle") != 0) {
+ fprintf (stderr,
+ "incorrect protocol \"%s\", expected
\"oldstyle\"\n", s);
+ exit (EXIT_FAILURE);
+ }
+
if ((r = nbd_get_size (nbd)) == -1) {
fprintf (stderr, "%s\n", nbd_get_error ());
exit (EXIT_FAILURE);
--
2.23.0