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 IP TOS (type-of-service) field
104 if ( inSettings->mTOS > 0 ) {
105 val = inSettings->mTOS;
106 rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_TOS, &val, len );
107 WARN_errno( rc == SOCKET_ERROR, "setsockopt IP_TOS" );
112 // TCP-specific options
113 if ( inSettings->mProtocol == kProto_TCP ) {
115 // set the TCP window size (socket buffer sizes)
116 // must occur before call to accept() for large window sizes
117 setsock_tcp_windowsize(inSettings->mSock, inSettings->mWinSize,
118 inSettings->mThreadMode == kMode_Client);
119 setsock_tcp_mss( inSettings->mSock, inSettings->mMSS );
122 if ( isNoDelay( inSettings ) ) {
124 rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_NODELAY,
126 WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_NODELAY" );
129 if ( inSettings->congAlgo ) {
130 len = strlen( inSettings->congAlgo );
131 rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION,
132 inSettings->congAlgo , len );
133 WARN_errno( rc == SOCKET_ERROR, "setsockopt TCP_CONGESTION" );
137 rc = set_buffer_sock_size(inSettings->mSock, inSettings->mWinSize,
138 inSettings->mThreadMode == kMode_Client);
139 WARN_errno( rc < 0 , "setsockopt for buffer size" );
141 // DCCP-specific options
142 if ( inSettings->mProtocol == kProto_DCCP ) {
144 * We use the service code SC:PERF (0x50455246) from
145 * draft-fairhurst-dccp-serv-codes to identify this service.
147 val = htonl(0x50455246); /* ALWAYS use htonl */
148 rc = setsockopt( inSettings->mSock, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
150 WARN_errno( rc == SOCKET_ERROR, "setsockopt DCCP_SOCKOPT_SERVICE" );
153 // reuse the address, so we can run if a former server was killed off
154 if (inSettings->mThreadMode == kMode_Listener) {
156 rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, &val, len);
157 WARN_errno( rc == SOCKET_ERROR, "setsockopt SO_REUSEADDR" );
161 void MakeSocket(thread_Settings *inSettings)
163 struct addrinfo *local = NULL, *src,
164 *remote = NULL, *dst, hints;
166 int rc, socktype = sockType(inSettings->mProtocol);
168 assert(inSettings->mLocalhost || inSettings->mHost);
170 memset(&inSettings->local, 0, sizeof(inSettings->local));
171 memset(&inSettings->peer, 0, sizeof(inSettings->peer));
172 sprintf(port, "%u", inSettings->mPort);
175 * Set up address hint structure
177 memset(&hints, 0, sizeof(hints));
178 hints.ai_family = inSettings->mSockAF;
179 hints.ai_socktype = socktype;
181 * CHEAT: getaddrinfo does not support SOCK_DCCP and using a zero
182 * ai_socktype will return IPv4 addresses first (which is bad on
183 * a dual-stack host). Pretend here to be UDP - this usually works.
185 if (inSettings->mProtocol == IPPROTO_DCCP)
186 hints.ai_socktype = SOCK_DGRAM;
188 /* only use addresses available on the host */
189 hints.ai_flags = AI_ADDRCONFIG;
190 if (inSettings->mSockAF == AF_INET6)
191 /* use v4-mapped-v6 if no v6 addresses found */
192 hints.ai_flags |= AI_V4MAPPED | AI_ALL;
195 * Obtain local/remote address information
197 if (inSettings->mLocalhost || inSettings->mThreadMode == kMode_Listener) {
198 if (inSettings->mLocalhost == NULL)
199 hints.ai_flags |= AI_PASSIVE;
200 if ((rc = getaddrinfo(inSettings->mLocalhost, port, &hints, &local)))
201 die("Can not resolve local address %s#%s: %s",
202 inSettings->mLocalhost ? : "(local)", port, gai_strerror(rc));
205 if (inSettings->mHost && inSettings->mThreadMode != kMode_Listener) {
206 if ((rc = getaddrinfo(inSettings->mHost, port, &hints, &remote)))
207 die("Can not resolve peer address %s#%s: %s",
208 inSettings->mHost, port, gai_strerror(rc));
212 * Iterate over all src/dst combination, exhausting dst first
214 for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
215 if (src && src->ai_family == AF_INET &&
216 dst && dst->ai_family == AF_INET6)
217 goto get_next_dst; /* v4 -> v6 is not possible */
219 inSettings->mSockAF = src ? src->ai_family : dst->ai_family;
220 inSettings->mSock = socket(inSettings->mSockAF, socktype,
221 inSettings->mProtocol);
222 if (inSettings->mSock < 0)
225 SetSocketOptions(inSettings);
228 if (bind(inSettings->mSock, src->ai_addr, src->ai_addrlen) < 0) {
229 close(inSettings->mSock);
233 break; /* bind-only completed successfully */
236 if (dst && connect(inSettings->mSock, dst->ai_addr, dst->ai_addrlen) == 0)
237 break; /* connection completed successfully */
238 close(inSettings->mSock);
240 if (dst && (dst = dst->ai_next))
243 if (src && (src = src->ai_next))
244 dst = remote; /* restart inner loop */
247 if (src == NULL && dst == NULL)
248 die("Can not create %s socket", protoName(inSettings->mProtocol));
250 if (SockAddr_isMulticast(src->ai_addr))
251 setMulticast(inSettings);
252 memcpy(&inSettings->local, src->ai_addr, src->ai_addrlen);
255 if (SockAddr_isMulticast(dst->ai_addr))
256 setMulticast(inSettings);
257 memcpy(&inSettings->peer, dst->ai_addr, dst->ai_addrlen);
263 freeaddrinfo(remote);
265 if (isMulticast(inSettings) && !isConnectionLess(inSettings))
266 die("Can not use %s with multicast.", protoName(inSettings->mProtocol));