Package: openbsd-inetd / 0.20221205-2~deb12u1

buftuning Patch series | download
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
162
163
164
165
--- a/inetd.8
+++ b/inetd.8
@@ -108,7 +108,7 @@ The fields of the configuration file are
 .Bd -unfilled -offset indent
 service name
 socket type
-protocol
+protocol[,sndbuf=size][,rcvbuf=size]
 wait/nowait[.max]
 user[.group] or user[:group]
 server program
@@ -120,7 +120,7 @@ based service, the entry would contain t
 .Bd -unfilled -offset indent
 service name/version
 socket type
-rpc/protocol
+rpc/protocol[,sndbuf=size][,rcvbuf=size]
 wait/nowait[.max]
 user[.group] or user[:group]
 server program
@@ -235,6 +235,30 @@ of
 is used to specify a socket in the
 .Ux Ns -domain .
 .Pp
+In addition to the protocol, the configuration file may specify the
+send and receive socket buffer sizes for the listening socket.
+This is especially useful for
+.Tn TCP
+as the window scale factor, which is based on the receive socket
+buffer size, is advertised when the connection handshake occurs,
+thus the socket buffer size for the server must be set on the listen socket.
+By increasing the socket buffer sizes, better
+.Tn TCP
+performance may be realized in some situations.
+The socket buffer sizes are specified by appending their values to
+the protocol specification as follows:
+.Bd -literal -offset indent
+tcp,rcvbuf=16384
+tcp,sndbuf=64k
+tcp,rcvbuf=64k,sndbuf=1m
+.Ed
+.Pp
+A literal value may be specified, or modified using
+.Sq k
+to indicate kilobytes or
+.Sq m
+to indicate megabytes.
+.Pp
 The
 .Em wait/nowait
 entry is used to tell
--- a/inetd.c
+++ b/inetd.c
@@ -198,6 +198,8 @@ struct	servtab {
 	int	se_socktype;		/* type of socket to use */
 	int	se_family;		/* address family */
 	char	*se_proto;		/* protocol used */
+	int	se_sndbuf;		/* sndbuf size */
+	int	se_rcvbuf;		/* rcvbuf size */
 	int	se_rpcprog;		/* rpc program number */
 	int	se_rpcversl;		/* rpc program lowest version */
 	int	se_rpcversh;		/* rpc program highest version */
@@ -1115,6 +1117,8 @@ getconfigent(void)
 {
 	struct servtab *sep, *tsep;
 	char *arg, *cp, *hostdelim, *s;
+	char *cp0, *buf0, *buf1, *sz0, *sz1;
+	int val;
 	int argc;
 
 	sep = calloc(1, sizeof(struct servtab));
@@ -1188,6 +1192,93 @@ more:
 
 	sep->se_proto = newstr(arg);
 
+#define	MALFORMED(arg) \
+do { \
+	syslog(LOG_ERR, "%s: malformed buffer size option `%s'", \
+	    sep->se_service, (arg)); \
+	goto more; \
+} while (0)
+
+#define	GETVAL(arg) \
+do { \
+	if (!isdigit(*(arg))) \
+		MALFORMED(arg); \
+	val = strtol((arg), &cp0, 10); \
+	if (cp0 != NULL) { \
+		if (cp0[1] != '\0') \
+			MALFORMED((arg)); \
+		if (cp0[0] == 'k') \
+			val *= 1024; \
+		if (cp0[0] == 'm') \
+			val *= 1024 * 1024; \
+	} \
+	if (val < 1) { \
+		syslog(LOG_ERR, "%s: invalid buffer size `%s'", \
+		    sep->se_service, (arg)); \
+		goto more; \
+	} \
+} while (0)
+
+#define	ASSIGN(arg) \
+do { \
+	if (strcmp((arg), "sndbuf") == 0) \
+		sep->se_sndbuf = val; \
+	else if (strcmp((arg), "rcvbuf") == 0) \
+		sep->se_rcvbuf = val; \
+	else \
+		MALFORMED((arg)); \
+} while (0)
+
+	/*
+	 * Extract the send and receive buffer sizes before parsing
+	 * the protocol.
+	 */
+	sep->se_sndbuf = sep->se_rcvbuf = 0;
+	buf0 = buf1 = sz0 = sz1 = NULL;
+	if ((buf0 = strchr(sep->se_proto, ',')) != NULL) {
+		/* Skip the , */
+		*buf0++ = '\0';
+
+		/* Check to see if another socket buffer size was specified. */
+		if ((buf1 = strchr(buf0, ',')) != NULL) {
+			/* Skip the , */
+			*buf1++ = '\0';
+
+			/* Make sure a 3rd one wasn't specified. */
+			if (strchr(buf1, ',') != NULL) {
+				syslog(LOG_ERR, "%s: too many buffer sizes",
+				    sep->se_service);
+				goto more;
+			}
+
+			/* Locate the size. */
+			if ((sz1 = strchr(buf1, '=')) == NULL)
+				MALFORMED(buf1);
+
+			/* Skip the = */
+			*sz1++ = '\0';
+		}
+
+		/* Locate the size. */
+		if ((sz0 = strchr(buf0, '=')) == NULL)
+			MALFORMED(buf0);
+
+		/* Skip the = */
+		*sz0++ = '\0';
+
+		GETVAL(sz0);
+		ASSIGN(buf0);
+
+		if (buf1 != NULL) {
+			GETVAL(sz1);
+			ASSIGN(buf1);
+		}
+	}
+
+#undef ASSIGN
+#undef GETVAL
+#undef MALFORMED
+
 	if (strcmp(sep->se_proto, "unix") == 0) {
 		sep->se_family = AF_UNIX;
 	} else {