File: so_linger.c

package info (click to toggle)
strace 6.1-0.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 64,424 kB
  • sloc: ansic: 160,349; sh: 9,223; makefile: 3,817; cpp: 944; awk: 353; perl: 267; exp: 62; sed: 9
file content (161 lines) | stat: -rw-r--r-- 5,129 bytes parent folder | download | duplicates (9)
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
/*
 * Check decoding of SO_LINGER socket option.
 *
 * Copyright (c) 2017-2021 Dmitry V. Levin <ldv@strace.io>
 * All rights reserved.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "tests.h"

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

static const char *errstr;

static int
get_linger(int fd, void *val, socklen_t *len)
{
	int rc = getsockopt(fd, SOL_SOCKET, SO_LINGER, val, len);
	errstr = sprintrc(rc);
	return rc;
}

static int
set_linger(int fd, void *val, socklen_t len)
{
	int rc = setsockopt(fd, SOL_SOCKET, SO_LINGER, val, len);
	errstr = sprintrc(rc);
	return rc;
}

int
main(void)
{
	TAIL_ALLOC_OBJECT_CONST_PTR(struct linger, linger);
	TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);

	const unsigned int sizeof_l_onoff = sizeof(linger->l_onoff);
	struct linger *const l_onoff = tail_alloc(sizeof_l_onoff);

	const unsigned int sizeof_l_onoff_truncated = sizeof_l_onoff - 1;
	struct linger *const l_onoff_truncated =
		tail_alloc(sizeof_l_onoff_truncated);

	const unsigned int sizeof_l_linger_truncated =
		offsetofend(struct linger, l_linger) - 1;
	struct linger *const l_linger_truncated =
		tail_alloc(sizeof_l_linger_truncated);

        int fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd < 0)
                perror_msg_and_skip("socket AF_UNIX SOCK_STREAM");

	/* classic getsockopt */
	*len = sizeof(*linger);
	get_linger(fd, linger, len);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
	       ", [%d]) = %s\n",
	       fd, linger->l_onoff, linger->l_linger, *len, errstr);

	/* classic setsockopt */
	linger->l_onoff = -15;
	linger->l_linger = -42;
	set_linger(fd, linger, sizeof(*linger));
	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
	       ", %d) = %s\n",
	       fd, linger->l_onoff, linger->l_linger,
	       (unsigned int) sizeof(*linger), errstr);

	/* setsockopt with optlen larger than necessary */
	set_linger(fd, linger, sizeof(*linger) + 1);
	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
	       ", %d) = %s\n",
	       fd, linger->l_onoff, linger->l_linger,
	       (unsigned int) sizeof(*linger) + 1, errstr);

	/* setsockopt with optlen < 0 - EINVAL */
	set_linger(fd, linger, -1U);
	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, -1) = %s\n",
	       fd, linger, errstr);

	/* setsockopt with optlen smaller than necessary - EINVAL */
	set_linger(fd, linger, sizeof(linger->l_onoff));
	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n",
	       fd, linger, (unsigned int) sizeof(linger->l_onoff), errstr);

	/* setsockopt optval EFAULT */
	set_linger(fd, &linger->l_linger, sizeof(*linger));
	printf("setsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %d) = %s\n",
	       fd, &linger->l_linger, (unsigned int) sizeof(*linger), errstr);

	/* getsockopt with zero optlen */
	*len = 0;
	get_linger(fd, linger, len);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [0]) = %s\n",
	       fd, linger, errstr);

	/* getsockopt with optlen larger than necessary - shortened */
	*len = sizeof(*linger) + 1;
	get_linger(fd, linger, len);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=%d}"
	       ", [%u => %d]) = %s\n",
	       fd, linger->l_onoff, linger->l_linger,
	       (unsigned int) sizeof(*linger) + 1, *len, errstr);

	/*
	 * getsockopt with optlen less than sizeof(linger->l_onoff):
	 * the part of struct linger.l_onoff is printed in hex.
	 */
	*len = sizeof_l_onoff_truncated;
	get_linger(fd, l_onoff_truncated, len);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=", fd);
	print_quoted_hex(l_onoff_truncated, *len);
	printf("}, [%d]) = %s\n", *len, errstr);

	/*
	 * getsockopt with optlen equals to sizeof(struct linger.l_onoff):
	 * struct linger.l_linger is not printed.
	 */
	*len = sizeof_l_onoff;
	get_linger(fd, l_onoff, len);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d}"
	       ", [%d]) = %s\n",
	       fd, l_onoff->l_onoff, *len, errstr);

	/*
	 * getsockopt with optlen greater than sizeof(struct linger.l_onoff)
	 * but smaller than sizeof(struct linger):
	 * the part of struct linger.l_linger is printed in hex.
	 */
	*len = sizeof_l_linger_truncated;
	get_linger(fd, l_linger_truncated, len);
	/*
	 * Copy to a properly aligned structure to avoid unaligned access
	 * to struct linger.l_onoff field.
	 */
	memcpy(linger, l_linger_truncated, sizeof_l_linger_truncated);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, {l_onoff=%d, l_linger=",
	       fd, linger->l_onoff);
	print_quoted_hex(&linger->l_linger, sizeof_l_linger_truncated -
					    offsetof(struct linger, l_linger));
	printf("}, [%d]) = %s\n", *len, errstr);

	/* getsockopt optval EFAULT */
	*len = sizeof(*linger);
	get_linger(fd, &linger->l_linger, len);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, [%d]) = %s\n",
	       fd, &linger->l_linger, *len, errstr);

	/* getsockopt optlen EFAULT */
	get_linger(fd, linger, len + 1);
	printf("getsockopt(%d, SOL_SOCKET, SO_LINGER, %p, %p) = %s\n",
	       fd, linger, len + 1, errstr);

	puts("+++ exited with 0 +++");
	return 0;
}