aboutgitcodebugslistschat
path: root/doc/platform-requirements/recv-zero.c
diff options
context:
space:
mode:
Diffstat (limited to 'doc/platform-requirements/recv-zero.c')
-rw-r--r--doc/platform-requirements/recv-zero.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/doc/platform-requirements/recv-zero.c b/doc/platform-requirements/recv-zero.c
new file mode 100644
index 0000000..2a2a561
--- /dev/null
+++ b/doc/platform-requirements/recv-zero.c
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* recv-zero.c
+ *
+ * Verify that we're able to discard datagrams by recv()ing into a zero-length
+ * buffer.
+ *
+ * Copyright Red Hat
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+
+#define DSTPORT 13257U
+
+enum discard_method {
+ DISCARD_NULL_BUF,
+ DISCARD_ZERO_IOV,
+ DISCARD_NULL_IOV,
+ NUM_METHODS,
+};
+
+/* 127.0.0.1:DSTPORT */
+static const struct sockaddr_in lo_dst = SOCKADDR_INIT(INADDR_LOOPBACK, DSTPORT);
+
+static void test_discard(enum discard_method method)
+{
+ struct iovec zero_iov = { .iov_base = NULL, .iov_len = 0, };
+ struct msghdr mh_zero = {
+ .msg_iov = &zero_iov,
+ .msg_iovlen = 1,
+ };
+ struct msghdr mh_null = {
+ .msg_iov = NULL,
+ .msg_iovlen = 0,
+ };
+ long token1, token2;
+ int recv_s, send_s;
+ ssize_t rc;
+
+ token1 = random();
+ token2 = random();
+
+ recv_s = sock_reuseaddr();
+ if (bind(recv_s, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+ die("bind(): %s\n", strerror(errno));
+
+ send_s = sock_reuseaddr();
+ if (connect(send_s, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+ die("connect(): %s\n", strerror(errno));
+
+ send_token(send_s, token1);
+ send_token(send_s, token2);
+
+ switch (method) {
+ case DISCARD_NULL_BUF:
+ /* cppcheck-suppress nullPointer */
+ rc = recv(recv_s, NULL, 0, MSG_DONTWAIT);
+ if (rc < 0)
+ die("discarding recv(): %s\n", strerror(errno));
+ break;
+
+ case DISCARD_ZERO_IOV:
+ rc = recvmsg(recv_s, &mh_zero, MSG_DONTWAIT);
+ if (rc < 0)
+ die("recvmsg() with zero-length buffer: %s\n",
+ strerror(errno));
+ if (!((unsigned)mh_zero.msg_flags & MSG_TRUNC))
+ die("Missing MSG_TRUNC flag\n");
+ break;
+
+ case DISCARD_NULL_IOV:
+ rc = recvmsg(recv_s, &mh_null, MSG_DONTWAIT);
+ if (rc < 0)
+ die("recvmsg() with zero-length iov: %s\n",
+ strerror(errno));
+ if (!((unsigned)mh_null.msg_flags & MSG_TRUNC))
+ die("Missing MSG_TRUNC flag\n");
+ break;
+
+ default:
+ die("Bad method\n");
+ }
+
+ recv_token(recv_s, token2);
+
+ /* cppcheck-suppress nullPointer */
+ rc = recv(recv_s, NULL, 0, MSG_DONTWAIT);
+ if (rc < 0 && errno != EAGAIN)
+ die("redundant discarding recv(): %s\n", strerror(errno));
+ if (rc >= 0)
+ die("Unexpected receive: rc=%zd\n", rc);
+}
+
+int main(int argc, char *argv[])
+{
+ enum discard_method method;
+
+ (void)argc;
+ (void)argv;
+
+ for (method = 0; method < NUM_METHODS; method++)
+ test_discard(method);
+
+ printf("Discarding datagrams with 0-length receives seems to work\n");
+
+ exit(0);
+}