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" );
130 rc = set_buffer_sock_size(inSettings->mSock, inSettings->mWinSize,
131 inSettings->mThreadMode == kMode_Client);
132 WARN_errno( rc < 0 , "setsockopt for buffer size" );
134 // DCCP-specific options
135 if ( inSettings->mProtocol == kProto_DCCP ) {
137 * We use the service code SC:PERF (0x50455246) from
138 * draft-fairhurst-dccp-serv-codes to identify this service.
140 val = htonl(0x50455246); /* ALWAYS use htonl */
141 rc = setsockopt( inSettings->mSock, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
143 WARN_errno( rc == SOCKET_ERROR, "setsockopt DCCP_SOCKOPT_SERVICE" );
146 // reuse the address, so we can run if a former server was killed off
147 if (inSettings->mThreadMode == kMode_Listener) {
149 rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, &val, len);
150 WARN_errno( rc == SOCKET_ERROR, "setsockopt SO_REUSEADDR" );
154 void MakeSocket(thread_Settings *inSettings)
156 struct addrinfo *local = NULL, *src,
157 *remote = NULL, *dst, hints;
159 int rc, socktype = sockType(inSettings->mProtocol);
161 assert(inSettings->mLocalhost || inSettings->mHost);
163 memset(&inSettings->local, 0, sizeof(inSettings->local));
164 memset(&inSettings->peer, 0, sizeof(inSettings->peer));
165 sprintf(port, "%u", inSettings->mPort);
168 * Set up address hint structure
170 memset(&hints, 0, sizeof(hints));
171 hints.ai_family = inSettings->mSockAF;
172 hints.ai_socktype = socktype;
174 * CHEAT: getaddrinfo does not support SOCK_DCCP and using a zero
175 * ai_socktype will return IPv4 addresses first (which is bad on
176 * a dual-stack host). Pretend here to be UDP - this usually works.
178 if (inSettings->mProtocol == IPPROTO_DCCP)
179 hints.ai_socktype = SOCK_DGRAM;
181 /* only use addresses available on the host */
182 hints.ai_flags = AI_ADDRCONFIG;
183 if (inSettings->mSockAF == AF_INET6)
184 /* use v4-mapped-v6 if no v6 addresses found */
185 hints.ai_flags |= AI_V4MAPPED | AI_ALL;
188 * Obtain local/remote address information
190 if (inSettings->mLocalhost || inSettings->mThreadMode == kMode_Listener) {
191 if (inSettings->mLocalhost == NULL)
192 hints.ai_flags |= AI_PASSIVE;
193 if ((rc = getaddrinfo(inSettings->mLocalhost, port, &hints, &local)))
194 die("Can not resolve local address %s#%s: %s",
195 inSettings->mLocalhost ? : "(local)", port, gai_strerror(rc));
198 if (inSettings->mHost && inSettings->mThreadMode != kMode_Listener) {
199 if ((rc = getaddrinfo(inSettings->mHost, port, &hints, &remote)))
200 die("Can not resolve peer address %s#%s: %s",
201 inSettings->mHost, port, gai_strerror(rc));
205 * Iterate over all src/dst combination, exhausting dst first
207 for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
208 if (src && src->ai_family == AF_INET &&
209 dst && dst->ai_family == AF_INET6)
210 goto get_next_dst; /* v4 -> v6 is not possible */
212 inSettings->mSockAF = src ? src->ai_family : dst->ai_family;
213 inSettings->mSock = socket(inSettings->mSockAF, socktype,
214 inSettings->mProtocol);
215 if (inSettings->mSock < 0)
218 SetSocketOptions(inSettings);
221 if (bind(inSettings->mSock, src->ai_addr, src->ai_addrlen) < 0) {
222 close(inSettings->mSock);
226 break; /* bind-only completed successfully */
229 if (dst && connect(inSettings->mSock, dst->ai_addr, dst->ai_addrlen) == 0)
230 break; /* connection completed successfully */
231 close(inSettings->mSock);
233 if (dst && (dst = dst->ai_next))
236 if (src && (src = src->ai_next))
237 dst = remote; /* restart inner loop */
240 if (src == NULL && dst == NULL)
241 die("Can not create %s socket", protoName(inSettings->mProtocol));
243 if (SockAddr_isMulticast(src->ai_addr))
244 setMulticast(inSettings);
245 memcpy(&inSettings->local, src->ai_addr, src->ai_addrlen);
248 if (SockAddr_isMulticast(dst->ai_addr))
249 setMulticast(inSettings);
250 memcpy(&inSettings->peer, dst->ai_addr, dst->ai_addrlen);
256 freeaddrinfo(remote);
258 if (isMulticast(inSettings) && !isConnectionLess(inSettings))
259 die("Can not use %s with multicast.", protoName(inSettings->mProtocol));