1 /*---------------------------------------------------------------
2 * Copyright (c) 1999,2000,2001,2002,2003
3 * The Board of Trustees of the University of Illinois
5 *---------------------------------------------------------------
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software (Iperf) and associated
8 * documentation files (the "Software"), to deal in the Software
9 * without restriction, including without limitation the
10 * rights to use, copy, modify, merge, publish, distribute,
11 * sublicense, and/or sell copies of the Software, and to permit
12 * persons to whom the Software is furnished to do
13 * so, subject to the following conditions:
16 * Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and
18 * the following disclaimers.
21 * Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimers in the documentation and/or other materials
24 * provided with the distribution.
27 * Neither the names of the University of Illinois, NCSA,
28 * nor the names of its contributors may be used to endorse
29 * or promote products derived from this Software without
30 * specific prior written permission.
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
34 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
36 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
37 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
38 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 * ________________________________________________________________
41 * National Laboratory for Applied Network Research
42 * National Center for Supercomputing Applications
43 * University of Illinois at Urbana-Champaign
44 * http://www.ncsa.uiuc.edu
45 * ________________________________________________________________
48 * by Mark Gates <mgates@nlanr.net>
49 * Ajay Tirumala <tirumala@ncsa.uiuc.edu>
50 * -------------------------------------------------------------------
51 * Has routines the Client and Server classes use in common for
52 * performance testing the network.
53 * Changes in version 1.2.0
54 * for extracting data from files
55 * -------------------------------------------------------------------
70 * ------------------------------------------------------------------- */
75 #include "PerfSocket.hpp"
76 #include "SocketAddr.h"
79 /* -------------------------------------------------------------------
80 * Set socket options before the listen() or connect() calls.
81 * These are optional performance tuning factors.
82 * ------------------------------------------------------------------- */
83 void SetSocketOptions( thread_Settings *inSettings )
86 Socklen_t len = sizeof(int);
88 // check if we're sending multicast, and set TTL
89 if (isMulticast(inSettings) && inSettings->mTTL > 0) {
90 val = inSettings->mTTL;
91 if (SockAddr_isIPv6(&inSettings->local))
92 rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
95 rc = setsockopt(inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL,
98 WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
102 // Set the DiffServ codepoint for IPv4 TOS or IPv6 traffic class
103 if ( inSettings->mTOS > 0 ) {
104 val = inSettings->mTOS;
106 if ( inSettings->mSockAF == AF_INET ) {
107 rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_TOS, &val, len );
108 WARN_errno( rc == SOCKET_ERROR, "setsockopt IP_TOS" );
111 #if defined(IPV6_TCLASS)
112 if ( inSettings->mSockAF == AF_INET6 ) {
113 rc = setsockopt( inSettings->mSock, IPPROTO_IPV6, IPV6_TCLASS, &val, len );
114 WARN_errno( rc == SOCKET_ERROR, "setsockopt IPV6_TCLASS" );
120 // TCP-specific options
121 if ( inSettings->mProtocol == kProto_TCP ) {
123 // set the TCP window size (socket buffer sizes)
124 // must occur before call to accept() for large window sizes
125 setsock_tcp_windowsize(inSettings->mSock, inSettings->mWinSize,
126 inSettings->mThreadMode == kMode_Client);
127 setsock_tcp_mss( inSettings->mSock, inSettings->mMSS );
130 if ( isNoDelay( inSettings ) ) {
132 rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_NODELAY,
134 WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_NODELAY" );
137 if ( inSettings->congAlgo ) {
138 len = strlen( inSettings->congAlgo );
139 rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION,
140 inSettings->congAlgo , len );
141 WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_CONGESTION" );
145 rc = set_buffer_sock_size(inSettings->mSock, inSettings->mWinSize,
146 inSettings->mThreadMode == kMode_Client);
147 WARN_errno( rc < 0 , "setsockopt for buffer size" );
149 // DCCP-specific options
150 if ( inSettings->mProtocol == kProto_DCCP ) {
152 * We use the service code SC:PERF (0x50455246) from
153 * draft-fairhurst-dccp-serv-codes to identify this service.
155 val = htonl(0x50455246); /* ALWAYS use htonl */
156 rc = setsockopt( inSettings->mSock, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
158 WARN_errno( rc == SOCKET_ERROR, "setsockopt DCCP_SOCKOPT_SERVICE" );
160 // UDP-Lite specific options
161 if ( inSettings->mProtocol == kProto_UDPLITE ) {
162 /* we set the checksum coverage for both directions */
163 rc = setsockopt(inSettings->mSock, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV,
164 &inSettings->cscov, len);
165 WARN_errno(rc == SOCKET_ERROR, "setsockopt UDPLITE_SEND_CSCOV");
167 rc = setsockopt(inSettings->mSock, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV,
168 &inSettings->cscov, len);
170 WARN_errno(rc == SOCKET_ERROR, "setsockopt UDPLITE_RECV_CSCOV");
173 // reuse the address, so we can run if a former server was killed off
174 if (inSettings->mThreadMode == kMode_Listener) {
176 rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, &val, len);
177 WARN_errno( rc == SOCKET_ERROR, "setsockopt SO_REUSEADDR" );
181 void MakeSocket(thread_Settings *inSettings)
183 struct addrinfo *local = NULL, *src,
184 *remote = NULL, *dst, hints;
186 int rc, socktype = sockType(inSettings->mProtocol);
188 assert(inSettings->mLocalhost || inSettings->mHost);
190 memset(&inSettings->local, 0, sizeof(inSettings->local));
191 memset(&inSettings->peer, 0, sizeof(inSettings->peer));
192 sprintf(port, "%u", inSettings->mPort);
195 * Set up address hint structure
197 memset(&hints, 0, sizeof(hints));
198 hints.ai_family = inSettings->mSockAF;
199 hints.ai_socktype = socktype;
201 * CHEAT: getaddrinfo does not support SOCK_DCCP and using a zero
202 * ai_socktype will return IPv4 addresses first (which is bad on
203 * a dual-stack host). Pretend here to be UDP - this usually works.
205 if (inSettings->mProtocol == IPPROTO_DCCP)
206 hints.ai_socktype = SOCK_DGRAM;
208 /* only use addresses available on the host */
209 hints.ai_flags = AI_ADDRCONFIG;
210 if (inSettings->mSockAF == AF_INET6)
211 /* use v4-mapped-v6 if no v6 addresses found */
212 hints.ai_flags |= AI_V4MAPPED | AI_ALL;
215 * Obtain local/remote address information
217 if (inSettings->mLocalhost || inSettings->mThreadMode == kMode_Listener) {
218 if (inSettings->mLocalhost == NULL)
219 hints.ai_flags |= AI_PASSIVE;
220 if ((rc = getaddrinfo(inSettings->mLocalhost, port, &hints, &local)))
221 die("Can not resolve local address %s#%s: %s",
222 inSettings->mLocalhost ? : "(local)", port, gai_strerror(rc));
225 if (inSettings->mHost && inSettings->mThreadMode != kMode_Listener) {
226 if ((rc = getaddrinfo(inSettings->mHost, port, &hints, &remote)))
227 die("Can not resolve peer address %s#%s: %s",
228 inSettings->mHost, port, gai_strerror(rc));
232 * Iterate over all src/dst combination, exhausting dst first
234 for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
235 if (src && src->ai_family == AF_INET &&
236 dst && dst->ai_family == AF_INET6)
237 goto get_next_dst; /* v4 -> v6 is not possible */
239 inSettings->mSockAF = src ? src->ai_family : dst->ai_family;
240 inSettings->mSock = socket(inSettings->mSockAF, socktype,
241 inSettings->mProtocol);
242 if (inSettings->mSock < 0)
245 SetSocketOptions(inSettings);
248 if (bind(inSettings->mSock, src->ai_addr, src->ai_addrlen) < 0) {
249 close(inSettings->mSock);
253 break; /* bind-only completed successfully */
256 if (dst && connect(inSettings->mSock, dst->ai_addr, dst->ai_addrlen) == 0)
257 break; /* connection completed successfully */
258 close(inSettings->mSock);
260 if (dst && (dst = dst->ai_next))
263 if (src && (src = src->ai_next))
264 dst = remote; /* restart inner loop */
267 if (src == NULL && dst == NULL)
268 die("Can not create %s socket", protoName(inSettings->mProtocol));
270 if (SockAddr_isMulticast(src->ai_addr))
271 setMulticast(inSettings);
272 memcpy(&inSettings->local, src->ai_addr, src->ai_addrlen);
275 if (SockAddr_isMulticast(dst->ai_addr))
276 setMulticast(inSettings);
277 memcpy(&inSettings->peer, dst->ai_addr, dst->ai_addrlen);
283 freeaddrinfo(remote);
285 if (isMulticast(inSettings) && !isConnectionLess(inSettings))
286 die("Can not use %s with multicast.", protoName(inSettings->mProtocol));