The next patch wants to use the MSG_MORE flag of send() where
available. In preparation for that, we need a flags parameter to
conn->send (always 0 for now), as well as a decision on whether we can
use send() or must stick with write() (think nbdkit -s).
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
server/internal.h | 3 +-
server/connections.c | 45 ++++++++++++++++++++++++----
server/crypto.c | 4 +--
server/protocol-handshake-newstyle.c | 22 +++++++-------
server/protocol-handshake-oldstyle.c | 2 +-
server/protocol.c | 20 ++++++-------
6 files changed, 66 insertions(+), 30 deletions(-)
diff --git a/server/internal.h b/server/internal.h
index 2ee5e23..50525f3 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -143,7 +143,8 @@ typedef int (*connection_recv_function) (struct connection *,
void *buf, size_t len)
__attribute__((__nonnull__ (1, 2)));
typedef int (*connection_send_function) (struct connection *,
- const void *buf, size_t len)
+ const void *buf, size_t len,
+ int flags)
__attribute__((__nonnull__ (1, 2)));
typedef void (*connection_close_function) (struct connection *)
__attribute__((__nonnull__ (1)));
diff --git a/server/connections.c b/server/connections.c
index b7d9a6a..1a749b6 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -38,6 +38,7 @@
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
+#include <sys/socket.h>
#include "internal.h"
@@ -50,7 +51,10 @@ static void free_connection (struct connection *conn);
/* Don't call these raw socket functions directly. Use conn->recv etc. */
static int raw_recv (struct connection *, void *buf, size_t len);
-static int raw_send (struct connection *, const void *buf, size_t len);
+static int raw_send_socket (struct connection *, const void *buf, size_t len,
+ int flags);
+static int raw_send_other (struct connection *, const void *buf, size_t len,
+ int flags);
static void raw_close (struct connection *);
int
@@ -268,6 +272,8 @@ static struct connection *
new_connection (int sockin, int sockout, int nworkers)
{
struct connection *conn;
+ int opt;
+ socklen_t optlen = sizeof opt;
conn = calloc (1, sizeof *conn);
if (conn == NULL) {
@@ -285,7 +291,10 @@ new_connection (int sockin, int sockout, int nworkers)
pthread_mutex_init (&conn->status_lock, NULL);
conn->recv = raw_recv;
- conn->send = raw_send;
+ if (getsockopt (sockout, SOL_SOCKET, SO_TYPE, &opt, &optlen) == 0)
+ conn->send = raw_send_socket;
+ else
+ conn->send = raw_send_other;
conn->close = raw_close;
return conn;
@@ -320,11 +329,37 @@ free_connection (struct connection *conn)
free (conn);
}
-/* Write buffer to conn->sockout and either succeed completely
- * (returns 0) or fail (returns -1).
+/* Write buffer to conn->sockout with send() and either succeed completely
+ * (returns 0) or fail (returns -1). flags is ignored for now.
*/
static int
-raw_send (struct connection *conn, const void *vbuf, size_t len)
+raw_send_socket (struct connection *conn, const void *vbuf, size_t len,
+ int flags)
+{
+ int sock = conn->sockout;
+ const char *buf = vbuf;
+ ssize_t r;
+
+ while (len > 0) {
+ r = send (sock, buf, len, 0);
+ if (r == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ buf += r;
+ len -= r;
+ }
+
+ return 0;
+}
+
+/* Write buffer to conn->sockout with write() and either succeed completely
+ * (returns 0) or fail (returns -1). flags is ignored.
+ */
+static int
+raw_send_other (struct connection *conn, const void *vbuf, size_t len,
+ int flags)
{
int sock = conn->sockout;
const char *buf = vbuf;
diff --git a/server/crypto.c b/server/crypto.c
index 978a843..3f87944 100644
--- a/server/crypto.c
+++ b/server/crypto.c
@@ -346,10 +346,10 @@ crypto_recv (struct connection *conn, void *vbuf, size_t len)
}
/* Write buffer to GnuTLS and either succeed completely
- * (returns 0) or fail (returns -1).
+ * (returns 0) or fail (returns -1). flags is ignored for now.
*/
static int
-crypto_send (struct connection *conn, const void *vbuf, size_t len)
+crypto_send (struct connection *conn, const void *vbuf, size_t len, int flags)
{
gnutls_session_t session = conn->crypto_session;
const char *buf = vbuf;
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index dac2032..6993c8e 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -63,7 +63,7 @@ send_newstyle_option_reply (struct connection *conn,
if (conn->send (conn,
&fixed_new_option_reply,
- sizeof fixed_new_option_reply) == -1) {
+ sizeof fixed_new_option_reply, 0) == -1) {
/* The protocol document says that the client is allowed to simply
* drop the connection after sending NBD_OPT_ABORT, or may read
* the reply.
@@ -94,18 +94,18 @@ send_newstyle_option_reply_exportname (struct connection *conn,
if (conn->send (conn,
&fixed_new_option_reply,
- sizeof fixed_new_option_reply) == -1) {
+ sizeof fixed_new_option_reply, 0) == -1) {
nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
return -1;
}
len = htobe32 (name_len);
- if (conn->send (conn, &len, sizeof len) == -1) {
+ if (conn->send (conn, &len, sizeof len, 0) == -1) {
nbdkit_error ("write: %s: %s: %m",
name_of_nbd_opt (option), "sending length");
return -1;
}
- if (conn->send (conn, exportname, name_len) == -1) {
+ if (conn->send (conn, exportname, name_len, 0) == -1) {
nbdkit_error ("write: %s: %s: %m",
name_of_nbd_opt (option), "sending export name");
return -1;
@@ -132,8 +132,8 @@ send_newstyle_option_reply_info_export (struct connection *conn,
if (conn->send (conn,
&fixed_new_option_reply,
- sizeof fixed_new_option_reply) == -1 ||
- conn->send (conn, &export, sizeof export) == -1) {
+ sizeof fixed_new_option_reply, 0) == -1 ||
+ conn->send (conn, &export, sizeof export, 0) == -1) {
nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
return -1;
}
@@ -161,9 +161,9 @@ send_newstyle_option_reply_meta_context (struct connection *conn,
if (conn->send (conn,
&fixed_new_option_reply,
- sizeof fixed_new_option_reply) == -1 ||
- conn->send (conn, &context, sizeof context) == -1 ||
- conn->send (conn, name, namelen) == -1) {
+ sizeof fixed_new_option_reply, 0) == -1 ||
+ conn->send (conn, &context, sizeof context, 0) == -1 ||
+ conn->send (conn, name, namelen, 0) == -1) {
nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
return -1;
}
@@ -292,7 +292,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
&handshake_finish,
(conn->cflags & NBD_FLAG_NO_ZEROES)
? offsetof (struct new_handshake_finish, zeroes)
- : sizeof handshake_finish) == -1) {
+ : sizeof handshake_finish, 0) == -1) {
nbdkit_error ("write: %s: %m", optname);
return -1;
}
@@ -656,7 +656,7 @@ protocol_handshake_newstyle (struct connection *conn)
handshake.version = htobe64 (NEW_VERSION);
handshake.gflags = htobe16 (gflags);
- if (conn->send (conn, &handshake, sizeof handshake) == -1) {
+ if (conn->send (conn, &handshake, sizeof handshake, 0) == -1) {
nbdkit_error ("write: %s: %m", "sending newstyle handshake");
return -1;
}
diff --git a/server/protocol-handshake-oldstyle.c b/server/protocol-handshake-oldstyle.c
index 8dc87f4..9fde1ca 100644
--- a/server/protocol-handshake-oldstyle.c
+++ b/server/protocol-handshake-oldstyle.c
@@ -84,7 +84,7 @@ protocol_handshake_oldstyle (struct connection *conn)
handshake.gflags = htobe16 (gflags);
handshake.eflags = htobe16 (eflags);
- if (conn->send (conn, &handshake, sizeof handshake) == -1) {
+ if (conn->send (conn, &handshake, sizeof handshake, 0) == -1) {
nbdkit_error ("write: %m");
return -1;
}
diff --git a/server/protocol.c b/server/protocol.c
index 6d519e7..0e054ee 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -398,7 +398,7 @@ send_simple_reply (struct connection *conn,
reply.handle = handle;
reply.error = htobe32 (nbd_errno (error, false));
- r = conn->send (conn, &reply, sizeof reply);
+ r = conn->send (conn, &reply, sizeof reply, 0);
if (r == -1) {
nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -406,7 +406,7 @@ send_simple_reply (struct connection *conn,
/* Send the read data buffer. */
if (cmd == NBD_CMD_READ && !error) {
- r = conn->send (conn, buf, count);
+ r = conn->send (conn, buf, count, 0);
if (r == -1) {
nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -439,7 +439,7 @@ send_structured_reply_read (struct connection *conn,
reply.type = htobe16 (NBD_REPLY_TYPE_OFFSET_DATA);
reply.length = htobe32 (count + sizeof offset_data);
- r = conn->send (conn, &reply, sizeof reply);
+ r = conn->send (conn, &reply, sizeof reply, 0);
if (r == -1) {
nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -447,13 +447,13 @@ send_structured_reply_read (struct connection *conn,
/* Send the offset + read data buffer. */
offset_data.offset = htobe64 (offset);
- r = conn->send (conn, &offset_data, sizeof offset_data);
+ r = conn->send (conn, &offset_data, sizeof offset_data, 0);
if (r == -1) {
nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
}
- r = conn->send (conn, buf, count);
+ r = conn->send (conn, buf, count, 0);
if (r == -1) {
nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -573,7 +573,7 @@ send_structured_reply_block_status (struct connection *conn,
reply.length = htobe32 (sizeof context_id +
nr_blocks * sizeof (struct block_descriptor));
- r = conn->send (conn, &reply, sizeof reply);
+ r = conn->send (conn, &reply, sizeof reply, 0);
if (r == -1) {
nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -581,7 +581,7 @@ send_structured_reply_block_status (struct connection *conn,
/* Send the base:allocation context ID. */
context_id = htobe32 (base_allocation_id);
- r = conn->send (conn, &context_id, sizeof context_id);
+ r = conn->send (conn, &context_id, sizeof context_id, 0);
if (r == -1) {
nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -589,7 +589,7 @@ send_structured_reply_block_status (struct connection *conn,
/* Send each block descriptor. */
for (i = 0; i < nr_blocks; ++i) {
- r = conn->send (conn, &blocks[i], sizeof blocks[i]);
+ r = conn->send (conn, &blocks[i], sizeof blocks[i], 0);
if (r == -1) {
nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
@@ -615,7 +615,7 @@ send_structured_reply_error (struct connection *conn,
reply.type = htobe16 (NBD_REPLY_TYPE_ERROR);
reply.length = htobe32 (0 /* no human readable error */ + sizeof error_data);
- r = conn->send (conn, &reply, sizeof reply);
+ r = conn->send (conn, &reply, sizeof reply, 0);
if (r == -1) {
nbdkit_error ("write error reply: %m");
return connection_set_status (conn, -1);
@@ -624,7 +624,7 @@ send_structured_reply_error (struct connection *conn,
/* Send the error. */
error_data.error = htobe32 (nbd_errno (error, flags & NBD_CMD_FLAG_DF));
error_data.len = htobe16 (0);
- r = conn->send (conn, &error_data, sizeof error_data);
+ r = conn->send (conn, &error_data, sizeof error_data, 0);
if (r == -1) {
nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
return connection_set_status (conn, -1);
--
2.20.1