| 12
 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 {
 |