This allows plugins (or filters) to read the export name which was
passed to the server from the client.
UNFINISHED:
- Needs tests
---
TODO | 8 ++++++
docs/nbdkit-plugin.pod | 39 ++++++++++++++++++++++++++++
server/connections.c | 1 +
server/internal.h | 1 +
server/protocol-handshake-newstyle.c | 30 ++++++++++++---------
server/public.c | 10 +++++++
6 files changed, 77 insertions(+), 12 deletions(-)
diff --git a/TODO b/TODO
index 49b60b1..2468d74 100644
--- a/TODO
+++ b/TODO
@@ -62,6 +62,12 @@ General ideas for improvements
and also look at the implementation of the -swap option in
nbd-client.
+* Clients should be able to list export names supported by plugins.
+ Current behaviour is not really correct: We only list the -e
+ parameter from the command line, which is different from the export
+ name(s) that a plugin might want to support. Probably we should
+ deprecate the -e option entirely since it does nothing useful.
+
Suggestions for plugins
-----------------------
@@ -190,3 +196,5 @@ using ‘#define NBDKIT_API_VERSION <version>’.
value) strings. nbdkit should know the possible keys for the plugin
and filters, and the type of the values, and both check and parse
them for the plugin.
+
+* Modify open() API so it takes an export name parameter.
diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod
index bb162e4..53687ad 100644
--- a/docs/nbdkit-plugin.pod
+++ b/docs/nbdkit-plugin.pod
@@ -362,6 +362,45 @@ requested, or -1 after calling C<nbdkit_error> if there is no
point in
continuing the current command. Attempts to sleep more than
C<INT_MAX> seconds are treated as an error.
+=head1 EXPORT NAME
+
+If the client negotiated an NBD export name with nbdkit then plugins
+may read this from any connected callbacks. Nbdkit's normal behaviour
+is to accept any export name passed by the client, log it in debug
+output, but otherwise ignore it. By using C<nbdkit_export_name>
+plugins may choose to filter by export name or serve different
+content.
+
+=head2 C<nbdkit_export_name>
+
+ const char *nbdkit_export_name (void);
+
+Return the optional NBD export name if one was negotiated with the
+current client (this uses thread-local magic so no parameter is
+required). The returned string is only valid while the client is
+connected, so if you need to store it in the plugin you must copy it.
+
+The export name is a free-form text string, it is not necessarily a
+path or filename and it does not need to begin with a C<'/'>
+character. The NBD protocol describes the empty string (C<"">) as a
+representing a "default export" or to be used in cases where the
+export name does not make sense.
+
+This may return C<NULL> which does I<not> indicate an error:
+
+=over 4
+
+=item *
+
+It only returns the export name when there is a connected client.
+
+=item *
+
+If the server is using the oldstyle protocol the client does not send
+an export name.
+
+=back
+
=head1 CALLBACKS
=head2 C<.name>
diff --git a/server/connections.c b/server/connections.c
index b582764..a1fea54 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -385,6 +385,7 @@ free_connection (struct connection *conn)
pthread_mutex_destroy (&conn->status_lock);
free (conn->handles);
+ free (conn->exportname);
free (conn);
}
diff --git a/server/internal.h b/server/internal.h
index 9314e8f..3bfc1a7 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -180,6 +180,7 @@ struct connection {
struct b_conn_handle *handles;
size_t nr_handles;
+ char *exportname;
uint32_t cflags;
uint16_t eflags;
bool using_tls;
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index 9ddc319..e1301a0 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -274,11 +274,17 @@ negotiate_handshake_newstyle_options (struct connection *conn)
if (conn_recv_full (conn, data, optlen,
"read: %s: %m", name_of_nbd_opt (option)) == -1)
return -1;
- /* Apart from printing it, ignore the export name. */
+ /* Print the export name and save it in the connection. */
data[optlen] = '\0';
- debug ("newstyle negotiation: %s: "
- "client requested export '%s' (ignored)",
+ debug ("newstyle negotiation: %s: client requested export '%s'",
name_of_nbd_opt (option), data);
+ free (conn->exportname);
+ conn->exportname = malloc (optlen+1);
+ if (conn->exportname == NULL) {
+ nbdkit_error ("malloc: %m");
+ return -1;
+ }
+ memcpy (conn->exportname, data, optlen+1);
/* We have to finish the handshake by sending handshake_finish. */
if (finish_newstyle_options (conn, &exportsize) == -1)
@@ -413,19 +419,19 @@ negotiate_handshake_newstyle_options (struct connection *conn)
continue;
}
- /* As with NBD_OPT_EXPORT_NAME we print the export name and then
- * ignore it.
+ /* As with NBD_OPT_EXPORT_NAME we print the export name and
+ * save it in the connection.
*/
- requested_exportname = malloc (exportnamelen+1);
- if (requested_exportname == NULL) {
+ free (conn->exportname);
+ conn->exportname = malloc (exportnamelen+1);
+ if (conn->exportname == NULL) {
nbdkit_error ("malloc: %m");
return -1;
}
- memcpy (requested_exportname, &data[4], exportnamelen);
- requested_exportname[exportnamelen] = '\0';
- debug ("newstyle negotiation: %s: "
- "client requested export '%s' (ignored)",
- optname, requested_exportname);
+ memcpy (conn->exportname, &data[4], exportnamelen);
+ conn->exportname[exportnamelen] = '\0';
+ debug ("newstyle negotiation: %s: client requested export
'%s'",
+ optname, conn->exportname);
/* The spec is confusing, but it is required that we send back
* NBD_INFO_EXPORT, even if the client did not request it!
diff --git a/server/public.c b/server/public.c
index 630de9b..eb7f996 100644
--- a/server/public.c
+++ b/server/public.c
@@ -379,3 +379,13 @@ nbdkit_nanosleep (unsigned sec, unsigned nsec)
return 0;
#endif
}
+
+const char *
+nbdkit_export_name (void)
+{
+ struct connection *conn = threadlocal_get_conn ();
+
+ if (!conn)
+ return NULL;
+ return conn->exportname;
+}
--
2.23.0