public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
blob b4fd8a940795288e930046bf21ab3eb4519d4b4d 3813 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
 
// SPDX-License-Identifier: GPL-2.0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int tcp_peek_offset_probe(sa_family_t af)
{
	int optv = 0;
	int ret = 0;
	int s;

	s = socket(af, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
	if (s < 0) {
		perror("Temporary TCP socket creation failed");
	} else {
		if (!setsockopt(s, SOL_SOCKET, SO_PEEK_OFF, &optv, sizeof(int)))
			ret = 1;
		close(s);
	}
	return ret;
}


static void tcp_peek_offset_set(int s, int offset)
{
	if (setsockopt(s, SOL_SOCKET, SO_PEEK_OFF, &offset, sizeof(offset)))
		perror("Failed to set SO_PEEK_OFF value\n");
}

static int tcp_peek_offset_get(int s)
{
	int offset;
	socklen_t len = sizeof(offset);

	if (getsockopt(s, SOL_SOCKET, SO_PEEK_OFF, &offset, &len))
		perror("Failed to get SO_PEEK_OFF value\n");
	return offset;
}

static int tcp_peek_offset_test(void)
{
	struct sockaddr a = { AF_INET, {0, }};
	int err = EXIT_FAILURE;
	int s[2] = {0, 0};
	int recv_sock = 0;
	int offset = 0;
	ssize_t len;
	char buf;

	s[0] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	s[1] = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

	if (s[0] < 0 || s[1] < 0) {
		perror("Temporary probe socket creation failed\n");
		goto out;
	}
	if (0 > bind(s[0], &a, sizeof(a))) {
		perror("Temporary probe socket bind() failed\n");
		goto out;
	}
	if (0 > getsockname(s[0], &a, &((socklen_t) { sizeof(a) }))) {
		perror("Temporary probe socket getsockname() failed\n");
		goto out;
	}
	if (0 > listen(s[0], 0)) {
		perror("Temporary probe socket listen() failed\n");
		goto out;
	}
	if (0 <= connect(s[1], &a, sizeof(a)) || errno != EINPROGRESS) {
		perror("Temporary probe socket connect() failed\n");
		goto out;
	}
	recv_sock = accept(s[0], NULL, NULL);
	if (recv_sock <= 0) {
		perror("Temporary probe socket accept() failed\n");
		goto out;
	}

	/* Some basic tests of getting/setting offset */
	offset = tcp_peek_offset_get(recv_sock);
	if (offset != -1) {
		perror("Initial value of socket offset not -1\n");
		goto out;
	}
	tcp_peek_offset_set(recv_sock, 0);
	offset = tcp_peek_offset_get(recv_sock);
	if (offset != 0) {
		perror("Failed to set socket offset to 0\n");
		goto out;
	}

	/* Transfer a message */
	if (0 >= send(s[1], (char *)("ab"), 2, 0) || errno != EINPROGRESS) {
		perror("Temporary probe socket send() failed\n");
		goto out;
	}
	/* Read first byte */
	len = recv(recv_sock, &buf, 1, MSG_PEEK);
	if (len != 1 || buf != 'a') {
		perror("Failed to read first byte of message\n");
		goto out;
	}
	offset = tcp_peek_offset_get(recv_sock);
	if (offset != 1) {
		perror("Offset not forwarded correctly at first byte\n");
		goto out;
	}
	/* Try to read beyond last byte */
	len = recv(recv_sock, &buf, 2, MSG_PEEK);
	if (len != 1 || buf != 'b') {
		perror("Failed to read last byte of message\n");
		goto out;
	}
	offset = tcp_peek_offset_get(recv_sock);
	if (offset != 2) {
		perror("Offset not forwarded correctly at last byte\n");
		goto out;
	}
	/* Flush message */
	len = recv(recv_sock, NULL, 2, MSG_TRUNC);
	if (len != 2) {
		perror("Failed to flush message\n");
		goto out;
	}
	offset = tcp_peek_offset_get(recv_sock);
	if (offset != 0) {
		perror("Offset not reverted correctly after flush\n");
		goto out;
	}

	printf("TCP with MSG_PEEK_OFF works correctly\n");
	err = EXIT_SUCCESS;
out:
	close(recv_sock);
	close(s[1]);
	close(s[0]);
	return err;
}

int main(int argc, char *argv[])
{
	int cap4 = 0, cap6 = 0;

	cap4 = tcp_peek_offset_probe(AF_INET);
	if (!cap4)
		printf("SO_PEEK_OFF not supported for TCP/IPv4\n");
	cap6 = tcp_peek_offset_probe(AF_INET6);
	if (!cap6)
		printf("SO_PEEK_OFF not supported for TCP/IPv6\n");
	if (!cap4 || !cap6)
		exit(EXIT_SUCCESS);

	exit(tcp_peek_offset_test());
}


debug log:

solving b4fd8a940795 ...
found b4fd8a940795 in https://archives.passt.top/passt-dev/20240822005449.457191-1-jmaloy@redhat.com/

applying [1/1] https://archives.passt.top/passt-dev/20240822005449.457191-1-jmaloy@redhat.com/
diff --git a/tools/testing/selftests/net/tcp_so_peek_off.c b/tools/testing/selftests/net/tcp_so_peek_off.c
new file mode 100644
index 000000000000..b4fd8a940795

Checking patch tools/testing/selftests/net/tcp_so_peek_off.c...
1:167: new blank line at EOF.
+
Applied patch tools/testing/selftests/net/tcp_so_peek_off.c cleanly.
warning: 1 line adds whitespace errors.

index at:
100644 b4fd8a940795288e930046bf21ab3eb4519d4b4d	tools/testing/selftests/net/tcp_so_peek_off.c

Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).