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