Postfix3.3.1
vstream_tweak.c
[詳解]
1 /*++
2 /* NAME
3 /* vstream_tweak 3
4 /* SUMMARY
5 /* performance tweaks
6 /* SYNOPSIS
7 /* #include <vstream.h>
8 /*
9 /* VSTREAM *vstream_tweak_sock(stream)
10 /* VSTREAM *stream;
11 /*
12 /* VSTREAM *vstream_tweak_tcp(stream)
13 /* VSTREAM *stream;
14 /* DESCRIPTION
15 /* vstream_tweak_sock() does a best effort to boost your
16 /* network performance on the specified generic stream.
17 /*
18 /* vstream_tweak_tcp() does a best effort to boost your
19 /* Internet performance on the specified TCP stream.
20 /*
21 /* Arguments:
22 /* .IP stream
23 /* The stream being boosted.
24 /* DIAGNOSTICS
25 /* Panics: interface violations.
26 /* LICENSE
27 /* .ad
28 /* .fi
29 /* The Secure Mailer license must be distributed with this software.
30 /* AUTHOR(S)
31 /* Wietse Venema
32 /* IBM T.J. Watson Research
33 /* P.O. Box 704
34 /* Yorktown Heights, NY 10598, USA
35 /*--*/
36 
37 /* System library. */
38 
39 #include <sys_defs.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <errno.h>
44 
45 /* Utility library. */
46 
47 #include <msg.h>
48 #include <vstream.h>
49 
50 /* Application-specific. */
51 
52 #ifdef HAS_IPV6
53 #define SOCKADDR_STORAGE struct sockaddr_storage
54 #else
55 #define SOCKADDR_STORAGE struct sockaddr
56 #endif
57 
58 /* vstream_tweak_sock - boost your generic network performance */
59 
61 {
63  struct sockaddr *sa = (struct sockaddr *) &ss;
64  SOCKADDR_SIZE sa_length = sizeof(ss);
65  int ret;
66 
67  /*
68  * If the caller doesn't know if this socket is AF_LOCAL, AF_INET, etc.,
69  * figure it out for them.
70  */
71  if ((ret = getsockname(vstream_fileno(fp), sa, &sa_length)) >= 0) {
72  switch (sa->sa_family) {
73 #ifdef AF_INET6
74  case AF_INET6:
75 #endif
76  case AF_INET:
77  ret = vstream_tweak_tcp(fp);
78  break;
79  }
80  }
81  return (ret);
82 }
83 
84 /* vstream_tweak_tcp - boost your TCP performance */
85 
87 {
88  const char *myname = "vstream_tweak_tcp";
89  int mss = 0;
90  SOCKOPT_SIZE mss_len = sizeof(mss);
91  int err;
92 
93  /*
94  * Avoid Nagle delays when VSTREAM buffers are smaller than the MSS.
95  *
96  * Forcing TCP_NODELAY to be "always on" would hurt performance in the
97  * common case where VSTREAM buffers are larger than the MSS.
98  *
99  * Instead we ask the kernel what the current MSS is, and take appropriate
100  * action. Linux <= 2.2 getsockopt(TCP_MAXSEG) always returns zero (or
101  * whatever value was stored last with setsockopt()).
102  *
103  * Some ancient FreeBSD kernels don't report 'host unreachable' errors with
104  * getsockopt(SO_ERROR), and then treat getsockopt(TCP_MAXSEG) as a NOOP,
105  * leaving the mss parameter value unchanged. To work around these two
106  * getsockopt() bugs we set mss = 0, which is a harmless value.
107  */
108  if ((err = getsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_MAXSEG,
109  (void *) &mss, &mss_len)) < 0
110  && errno != ECONNRESET) {
111  msg_warn("%s: getsockopt TCP_MAXSEG: %m", myname);
112  return (err);
113  }
114  if (msg_verbose)
115  msg_info("%s: TCP_MAXSEG %d", myname, mss);
116 
117  /*
118  * Fix for recent Postfix versions: increase the VSTREAM buffer size if
119  * it is smaller than the MSS. Note: the MSS may change when the route
120  * changes and IP path MTU discovery is turned on, so we choose a
121  * somewhat larger buffer.
122  *
123  * Note: as of 20120527, the CA_VSTREAM_CTL_BUFSIZE request can reduce the
124  * stream buffer size to less than VSTREAM_BUFSIZE, when the request is
125  * made before the first stream read or write operation. We don't want to
126  * reduce the buffer size.
127  */
128 #define EFF_BUFFER_SIZE(fp) (vstream_req_bufsize(fp) ? \
129  vstream_req_bufsize(fp) : VSTREAM_BUFSIZE)
130 
131 #ifdef CA_VSTREAM_CTL_BUFSIZE
132  if (mss > EFF_BUFFER_SIZE(fp) / 2) {
133  if (mss < INT_MAX / 2)
134  mss *= 2;
135  vstream_control(fp,
138  }
139 
140  /*
141  * Workaround for older Postfix versions: turn on TCP_NODELAY if the
142  * VSTREAM buffer size is smaller than the MSS.
143  */
144 #else
145  if (mss > VSTREAM_BUFSIZE) {
146  int nodelay = 1;
147 
148  if ((err = setsockopt(vstream_fileno(fp), IPPROTO_TCP, TCP_NODELAY,
149  (void *) &nodelay, sizeof(nodelay))) < 0
150  && errno != ECONNRESET)
151  msg_warn("%s: setsockopt TCP_NODELAY: %m", myname);
152  }
153 #endif
154  return (err);
155 }
int msg_verbose
Definition: msg.c:177
int vstream_tweak_tcp(VSTREAM *fp)
Definition: vstream_tweak.c:86
#define SOCKADDR_SIZE
Definition: sys_defs.h:1411
#define SOCKOPT_SIZE
Definition: sys_defs.h:1415
#define CA_VSTREAM_CTL_BUFSIZE(v)
Definition: vstream.h:169
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define SOCKADDR_STORAGE
Definition: vstream_tweak.c:55
#define VSTREAM_BUFSIZE
Definition: vstream.h:92
int vstream_tweak_sock(VSTREAM *fp)
Definition: vstream_tweak.c:60
#define vstream_fileno(vp)
Definition: vstream.h:115
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
#define EFF_BUFFER_SIZE(fp)
void msg_info(const char *fmt,...)
Definition: msg.c:199