[PATCH 4/4] Implement negotiation of structured replies
From: Wouter Verhelst <w@uter.be>
This should make it possible for us to use structured replies!
Signed-off-by: Wouter Verhelst <w@uter.be>
---
cliserv.h | 13 +++++++------
nbd-server.c | 28 ++++++++++++++++++++++++++++
nbd.h | 1 +
3 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/cliserv.h b/cliserv.h
index 1333802..8a89c04 100644
--- a/cliserv.h
+++ b/cliserv.h
@@ -95,12 +95,13 @@ int writeit(int f, void *buf, size_t len);
* served */
/* Options that the client can select to the server */
-#define NBD_OPT_EXPORT_NAME (1) /**< Client wants to select a named export (is followed by name of export) */
-#define NBD_OPT_ABORT (2) /**< Client wishes to abort negotiation */
-#define NBD_OPT_LIST (3) /**< Client request list of supported exports (not followed by data) */
-#define NBD_OPT_STARTTLS (5) /**< Client wishes to initiate TLS */
-#define NBD_OPT_INFO (6) /**< Client wants information about the given export */
-#define NBD_OPT_GO (7) /**< Client wants to select the given and move to the transmission phase */
+#define NBD_OPT_EXPORT_NAME (1) /**< Client wants to select a named export (is followed by name of export) */
+#define NBD_OPT_ABORT (2) /**< Client wishes to abort negotiation */
+#define NBD_OPT_LIST (3) /**< Client request list of supported exports (not followed by data) */
+#define NBD_OPT_STARTTLS (5) /**< Client wishes to initiate TLS */
+#define NBD_OPT_INFO (6) /**< Client wants information about the given export */
+#define NBD_OPT_GO (7) /**< Client wants to select the given and move to the transmission phase */
+#define NBD_OPT_STRUCTURED_REPLY (8) /**< Client wants to see structured replies */
/* Replies the server can send during negotiation */
#define NBD_REP_ACK (1) /**< ACK a request. Data: option number to be acked */
diff --git a/nbd-server.c b/nbd-server.c
index 8c84f93..0b269d7 100644
--- a/nbd-server.c
+++ b/nbd-server.c
@@ -2181,6 +2181,8 @@ void send_export_info(CLIENT* client, SERVER* server, bool maybe_zeroes) {
flags |= NBD_FLAG_SEND_TRIM;
if (!(server->flags & F_COPYONWRITE))
flags |= NBD_FLAG_CAN_MULTI_CONN;
+ if (client->clientflags & F_STRUCTURED)
+ flags |= NBD_FLAG_SEND_DF;
flags = htons(flags);
socket_write(client, &flags, sizeof(flags));
if (!(glob_flags & F_NO_ZEROES) && maybe_zeroes) {
@@ -2521,6 +2523,27 @@ exit:
}
#endif
+/**
+ * Handle an NBD_OPT_STRUCTURED_REPLY message
+ */
+static void handle_structured_reply(CLIENT *client, uint32_t opt, GArray *servers, uint32_t cflags) {
+ uint32_t len;
+ int i;
+
+ socket_read(client, &len, sizeof(len));
+ len = ntohl(len);
+ if(len) {
+ send_reply(client, opt, NBD_REP_ERR_INVALID, -1, "NBD_OPT_STRUCTURED_REPLY with nonzero data length is not a valid request");
+ char buf[1024];
+ consume(client, len, buf, sizeof buf);
+ }
+ if(client->clientflags & F_STRUCTURED) {
+ send_reply(client, opt, NBD_REP_ERR_INVALID, -1, "NBD_OPT_STRUCTURED_REPLY has already been called");
+ }
+ client->clientflags |= F_STRUCTURED;
+ send_reply(client, opt, NBD_REP_ACK, 0, NULL);
+}
+
/**
* Handle an NBD_OPT_INFO or NBD_OPT_GO request.
*/
@@ -2700,6 +2723,8 @@ CLIENT* negotiate(int net, GArray* servers, struct generic_conf *genconf) {
// can't recover from failed TLS negotiation.
goto handler_err;
}
+ // once TLS has been negotiated, any state must be cleared
+ client->clientflags = 0;
#endif
break;
case NBD_OPT_GO:
@@ -2708,6 +2733,9 @@ CLIENT* negotiate(int net, GArray* servers, struct generic_conf *genconf) {
return client;
}
break;
+ case NBD_OPT_STRUCTURED_REPLY:
+ handle_structured_reply(client, opt, servers, cflags);
+ break;
default:
consume_len(client);
send_reply(client, opt, NBD_REP_ERR_UNSUP, -1, "The given option is unknown to this server implementation");
diff --git a/nbd.h b/nbd.h
index 4cf692a..4985e51 100644
--- a/nbd.h
+++ b/nbd.h
@@ -55,6 +55,7 @@ enum {
#define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */
#define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */
#define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send NBD_CMD_WRITE_ZEROES */
+#define NBD_FLAG_SEND_DF (1 << 7) /* Send NBD_CMD_FLAG_DF */
#define NBD_FLAG_CAN_MULTI_CONN (1 << 8) /* multiple connections are okay */
#define nbd_cmd(req) ((req)->cmd[0])
--
2.39.2
Reply to: