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" );
161 // reuse the address, so we can run if a former server was killed off
162 if (inSettings->mThreadMode == kMode_Listener) {
164 rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, &val, len);
165 WARN_errno( rc == SOCKET_ERROR, "setsockopt SO_REUSEADDR" );
169 void MakeSocket(thread_Settings *inSettings)
171 struct addrinfo *local = NULL, *src,
172 *remote = NULL, *dst, hints;
174 int rc, socktype = sockType(inSettings->mProtocol);
176 assert(inSettings->mLocalhost || inSettings->mHost);
178 memset(&inSettings->local, 0, sizeof(inSettings->local));
179 memset(&inSettings->peer, 0, sizeof(inSettings->peer));
180 sprintf(port, "%u", inSettings->mPort);
183 * Set up address hint structure
185 memset(&hints, 0, sizeof(hints));
186 hints.ai_family = inSettings->mSockAF;
187 hints.ai_socktype = socktype;
189 * CHEAT: getaddrinfo does not support SOCK_DCCP and using a zero
190 * ai_socktype will return IPv4 addresses first (which is bad on
191 * a dual-stack host). Pretend here to be UDP - this usually works.
193 if (inSettings->mProtocol == IPPROTO_DCCP)
194 hints.ai_socktype = SOCK_DGRAM;
196 /* only use addresses available on the host */
197 hints.ai_flags = AI_ADDRCONFIG;
198 if (inSettings->mSockAF == AF_INET6)
199 /* use v4-mapped-v6 if no v6 addresses found */
200 hints.ai_flags |= AI_V4MAPPED | AI_ALL;
203 * Obtain local/remote address information
205 if (inSettings->mLocalhost || inSettings->mThreadMode == kMode_Listener) {
206 if (inSettings->mLocalhost == NULL)
207 hints.ai_flags |= AI_PASSIVE;
208 if ((rc = getaddrinfo(inSettings->mLocalhost, port, &hints, &local)))
209 die("Can not resolve local address %s#%s: %s",
210 inSettings->mLocalhost ? : "(local)", port, gai_strerror(rc));
213 if (inSettings->mHost && inSettings->mThreadMode != kMode_Listener) {
214 if ((rc = getaddrinfo(inSettings->mHost, port, &hints, &remote)))
215 die("Can not resolve peer address %s#%s: %s",
216 inSettings->mHost, port, gai_strerror(rc));
220 * Iterate over all src/dst combination, exhausting dst first
222 for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
223 if (src && src->ai_family == AF_INET &&
224 dst && dst->ai_family == AF_INET6)
225 goto get_next_dst; /* v4 -> v6 is not possible */
227 inSettings->mSockAF = src ? src->ai_family : dst->ai_family;
228 inSettings->mSock = socket(inSettings->mSockAF, socktype,
229 inSettings->mProtocol);
230 if (inSettings->mSock < 0)
233 SetSocketOptions(inSettings);
236 if (bind(inSettings->mSock, src->ai_addr, src->ai_addrlen) < 0) {
237 close(inSettings->mSock);
241 break; /* bind-only completed successfully */
244 if (dst && connect(inSettings->mSock, dst->ai_addr, dst->ai_addrlen) == 0)
245 break; /* connection completed successfully */
246 close(inSettings->mSock);
248 if (dst && (dst = dst->ai_next))
251 if (src && (src = src->ai_next))
252 dst = remote; /* restart inner loop */
255 if (src == NULL && dst == NULL)
256 die("Can not create %s socket", protoName(inSettings->mProtocol));
258 if (SockAddr_isMulticast(src->ai_addr))
259 setMulticast(inSettings);
260 memcpy(&inSettings->local, src->ai_addr, src->ai_addrlen);
263 if (SockAddr_isMulticast(dst->ai_addr))
264 setMulticast(inSettings);
265 memcpy(&inSettings->peer, dst->ai_addr, dst->ai_addrlen);
271 freeaddrinfo(remote);
273 if (isMulticast(inSettings) && !isConnectionLess(inSettings))
274 die("Can not use %s with multicast.", protoName(inSettings->mProtocol));