xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/vstream_tweak.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	$NetBSD: vstream_tweak.c,v 1.1.1.1 2009/06/23 10:09:01 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	vstream_tweak 3
6 /* SUMMARY
7 /*	performance tweaks
8 /* SYNOPSIS
9 /*	#include <vstream.h>
10 /*
11 /*	VSTREAM	*vstream_tweak_sock(stream)
12 /*	VSTREAM	*stream;
13 /*
14 /*	VSTREAM	*vstream_tweak_tcp(stream)
15 /*	VSTREAM	*stream;
16 /* DESCRIPTION
17 /*	vstream_tweak_sock() does a best effort to boost your
18 /*	network performance on the specified generic stream.
19 /*
20 /*	vstream_tweak_tcp() does a best effort to boost your
21 /*	Internet performance on the specified TCP stream.
22 /*
23 /*	Arguments:
24 /* .IP stream
25 /*	The stream being boosted.
26 /* DIAGNOSTICS
27 /*	Panics: interface violations.
28 /* LICENSE
29 /* .ad
30 /* .fi
31 /*	The Secure Mailer license must be distributed with this software.
32 /* AUTHOR(S)
33 /*	Wietse Venema
34 /*	IBM T.J. Watson Research
35 /*	P.O. Box 704
36 /*	Yorktown Heights, NY 10598, USA
37 /*--*/
38 
39 /* System library. */
40 
41 #include <sys_defs.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45 
46 /* Utility library. */
47 
48 #include <msg.h>
49 #include <vstream.h>
50 
51 /* Application-specific. */
52 
53 #ifdef HAS_IPV6
54 #define SOCKADDR_STORAGE struct sockaddr_storage
55 #else
56 #define SOCKADDR_STORAGE struct sockaddr
57 #endif
58 
59 /* vstream_tweak_sock - boost your generic network performance */
60 
61 int     vstream_tweak_sock(VSTREAM *fp)
62 {
63     SOCKADDR_STORAGE ss;
64     struct sockaddr *sa = (struct sockaddr *) & ss;
65     SOCKADDR_SIZE sa_length = sizeof(ss);
66     int     ret;
67 
68     /*
69      * If the caller doesn't know if this socket is AF_LOCAL, AF_INET, etc.,
70      * figure it out for them.
71      */
72     if ((ret = getsockname(vstream_fileno(fp), sa, &sa_length)) >= 0) {
73 	switch (sa->sa_family) {
74 #ifdef AF_INET6
75 	case AF_INET6:
76 #endif
77 	case AF_INET:
78 	    ret = vstream_tweak_tcp(fp);
79 	    break;
80 	}
81     }
82     return (ret);
83 }
84 
85 /* vstream_tweak_tcp - boost your TCP performance */
86 
87 int     vstream_tweak_tcp(VSTREAM *fp)
88 {
89     const char *myname = "vstream_tweak_tcp";
90     int     mss;
91     SOCKOPT_SIZE mss_len = sizeof(mss);
92     int     err;
93 
94     /*
95      * Avoid Nagle delays when VSTREAM buffers are smaller than the MSS.
96      *
97      * Forcing TCP_NODELAY to be "always on" would hurt performance in the
98      * common case where VSTREAM buffers are larger than the MSS.
99      *
100      * Instead we ask the kernel what the current MSS is, and take appropriate
101      * action. Linux <= 2.2 getsockopt(TCP_MAXSEG) always returns zero (or
102      * whatever value was stored last with setsockopt()).
103      */
104     if ((err = getsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_MAXSEG,
105 			  (char *) &mss, &mss_len)) < 0) {
106 	msg_warn("%s: getsockopt TCP_MAXSEG: %m", myname);
107 	return (err);
108     }
109     if (msg_verbose)
110 	msg_info("%s: TCP_MAXSEG %d", myname, mss);
111 
112     /*
113      * Fix for recent Postfix versions: increase the VSTREAM buffer size if
114      * the VSTREAM buffer is smaller than the MSS. Note: the MSS may change
115      * when the route changes and IP path MTU discovery is turned on, so we
116      * choose a somewhat larger buffer.
117      */
118 #ifdef VSTREAM_CTL_BUFSIZE
119     if (mss > 0) {
120 	if (mss < INT_MAX / 2)
121 	    mss *= 2;
122 	vstream_control(fp,
123 			VSTREAM_CTL_BUFSIZE, (ssize_t) mss,
124 			VSTREAM_CTL_END);
125     }
126 
127     /*
128      * Workaround for older Postfix versions: turn on TCP_NODELAY if the
129      * VSTREAM buffer size is smaller than the MSS.
130      */
131 #else
132     if (mss > VSTREAM_BUFSIZE) {
133 	int     nodelay = 1;
134 
135 	if ((err = setsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_NODELAY,
136 			      (char *) &nodelay, sizeof(nodelay))) < 0)
137 	    msg_warn("%s: setsockopt TCP_NODELAY: %m", myname);
138     }
139 #endif
140     return (err);
141 }
142