/* -------------------------------------------------------------------
* Listens for connections and starts Servers to handle data.
* For TCP, each accepted connection spawns a Server thread.
- * For UDP, handle all data in this thread for Win32 Only, otherwise
- * spawn a new Server thread.
+ * For datagram-oriented protocols, spawn a new Server thread.
* ------------------------------------------------------------------- */
-void Listener::Run( void ) {
+void Listener::Run(void)
+{
#ifdef sun
- if ( ( isUDP( mSettings ) &&
- isMulticast( mSettings ) &&
- !isSingleUDP( mSettings ) ) ||
- isSingleUDP( mSettings ) ) {
+ if ( ( isPacketOriented( mSettings ) &&
+ isMulticast( mSettings ) &&
+ !isSingleUDP( mSettings ) ) || isSingleUDP( mSettings ) ) {
UDPSingleServer();
- } else
#else
if ( isSingleUDP( mSettings ) ) {
UDPSingleServer();
- } else
#endif
- {
- bool client = false, UDP = isUDP( mSettings ), mCount = (mSettings->mThreads != 0);
+ } else {
+ bool client = (mSettings->mHost != NULL),
+ mCount = (mSettings->mThreads != 0);
thread_Settings *tempSettings = NULL;
Iperf_ListEntry *exist, *listtemp;
- client_hdr* hdr = ( UDP ? (client_hdr*) (((UDP_datagram*)mBuf) + 1) :
- (client_hdr*) mBuf);
-
- if ( mSettings->mHost != NULL ) {
- client = true;
- SockAddr_remoteAddr( mSettings );
- }
+ client_hdr* hdr;
+
Settings_Copy( mSettings, &server );
server->mThreadMode = kMode_Server;
-
-
+
// Accept each packet,
// If there is no existing client, then start
// a new thread to service the new client
close( server->mSock );
break;
}
+
// Reset Single Client Stuff
if ( isSingleClient( mSettings ) && clients == NULL ) {
- mSettings->peer = server->peer;
mClients--;
client = true;
// Once all the server threads exit then quit
mClients = 1;
}
}
- // Verify that it is allowed
- if ( client ) {
- if ( !SockAddr_Hostare_Equal( (sockaddr*) &mSettings->peer,
- (sockaddr*) &server->peer ) ) {
- // Not allowed try again
- close( server->mSock );
- if ( isUDP( mSettings ) ) {
- mSettings->mSock = -1;
- Listen();
- }
- continue;
- }
- }
+ // Copy peer address for individual/bidirectional dual-test
+ // NOTE: There is no longer a reverse-lookup for the peer to
+ // check if it is allowed. The reason is that it simply
+ // gets too complex: compare v4/v6, v4/v4, v6/v4, v6/v6
+ if (client)
+ mSettings->peer = server->peer;
// Create an entry for the connection list
listtemp = new Iperf_ListEntry;
- memcpy(listtemp, &server->peer, sizeof(iperf_sockaddr));
+ memcpy(listtemp, &server->peer, sizeof(server->peer));
listtemp->next = NULL;
// See if we need to do summing
tempSettings = NULL;
if ( !isCompat( mSettings ) && !isMulticast( mSettings ) ) {
- if ( !UDP ) {
- // TCP does not have the info yet
+ if ( !isConnectionLess(mSettings)) {
+ hdr = (client_hdr*) mBuf;
+
+ // TCP/DCCP does not have the info yet
if ( recv( server->mSock, (char*)hdr, sizeof(client_hdr), 0) > 0 ) {
- Settings_GenerateClientSettings( server, &tempSettings,
- hdr );
+ Settings_GenerateClientSettings( server, &tempSettings, hdr );
}
} else {
- Settings_GenerateClientSettings( server, &tempSettings,
- hdr );
+ hdr = (client_hdr *) ( ((dgram_record*)mBuf) + 1 );
+ Settings_GenerateClientSettings( server, &tempSettings, hdr );
}
}
-
if ( tempSettings != NULL ) {
client_init( tempSettings );
if ( tempSettings->mMode == kTest_DualTest ) {
thread_start( server );
// create a new socket
- if ( UDP ) {
+ if ( isConnectionLess( mSettings ) ) {
mSettings->mSock = -1;
Listen( );
}
/* -------------------------------------------------------------------
* Setup a socket listening on a port.
- * For TCP, this calls bind() and listen().
- * For UDP, this just calls bind().
+ * For connection-oriented protocols, this calls bind() and listen().
+ * For connection-less protocols, this just calls bind().
* If inLocalhost is not null, bind to that address rather than the
* wildcard server address, specifying what incoming interface to
* accept connections on.
* ------------------------------------------------------------------- */
-void Listener::Listen( ) {
- int rc;
-
- SockAddr_localAddr( mSettings );
-
- // create an internet TCP socket
- int type = (isUDP( mSettings ) ? SOCK_DGRAM : SOCK_STREAM);
- int domain = (SockAddr_isIPv6( &mSettings->local ) ?
-#ifdef HAVE_IPV6
- AF_INET6
-#else
- AF_INET
-#endif
- : AF_INET);
-
- mSettings->mSock = socket( domain, type, 0 );
- WARN_errno( mSettings->mSock == INVALID_SOCKET, "socket" );
-
- SetSocketOptions( mSettings );
-
- // reuse the address, so we can run if a former server was killed off
- int boolean = 1;
- Socklen_t len = sizeof(boolean);
- setsockopt( mSettings->mSock, SOL_SOCKET, SO_REUSEADDR, (char*) &boolean, len );
+void Listener::Listen()
+{
+ MakeSocket(mSettings);
- // bind socket to server address
- rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local );
- WARN_errno( rc == SOCKET_ERROR, "bind" );
-
- // listen for connections (TCP only).
// default backlog traditionally 5
- if ( !isUDP( mSettings ) ) {
- rc = listen( mSettings->mSock, 5 );
- WARN_errno( rc == SOCKET_ERROR, "listen" );
- }
+ if (!isConnectionLess(mSettings) && listen(mSettings->mSock, 5) < 0)
+ WARN_errno( 1, "listen" );
- // if multicast, join the group
- if ( SockAddr_isMulticast( &mSettings->local ) ) {
- McastJoin( );
- }
-} // end Listen
+ // if multicast, join the group specified earlier via -B
+ if (isMulticast(mSettings))
+ McastJoin();
+}
/* -------------------------------------------------------------------
* Joins the multicast group, with the default interface.
* ------------------------------------------------------------------- */
-void Listener::McastJoin( ) {
-#ifdef HAVE_MULTICAST
- if ( !SockAddr_isIPv6( &mSettings->local ) ) {
- struct ip_mreq mreq;
+void Listener::McastJoin()
+{
+ if (SockAddr_isIPv6(&mSettings->local)) {
+ struct ipv6_mreq mreq;
- memcpy( &mreq.imr_multiaddr, SockAddr_get_in_addr( &mSettings->local ),
- sizeof(mreq.imr_multiaddr));
+ memset(&mreq, 0, sizeof(mreq));
+ memcpy(&mreq.ipv6mr_multiaddr, &((struct sockaddr_in6*)&mSettings->local)->sin6_addr,
+ sizeof(mreq.ipv6mr_multiaddr));
- mreq.imr_interface.s_addr = htonl( INADDR_ANY );
+ mreq.ipv6mr_interface = mSettings->mMcastIface;
- int rc = setsockopt( mSettings->mSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- (char*) &mreq, sizeof(mreq));
- WARN_errno( rc == SOCKET_ERROR, "multicast join" );
- }
-#ifdef HAVE_IPV6_MULTICAST
- else {
- struct ipv6_mreq mreq;
+ if (setsockopt(mSettings->mSock, IPPROTO_IPV6,
+ IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+ die("IPv6 multicast join failed: did you use -j/-J?");
- memcpy( &mreq.ipv6mr_multiaddr, SockAddr_get_in6_addr( &mSettings->local ),
- sizeof(mreq.ipv6mr_multiaddr));
+ } else {
+ struct ip_mreqn mreq;
+
+ memset(&mreq, 0, sizeof(mreq));
+ memcpy(&mreq.imr_multiaddr, &((struct sockaddr_in*)&mSettings->local)->sin_addr,
+ sizeof(mreq.imr_multiaddr));
- mreq.ipv6mr_interface = 0;
+ mreq.imr_ifindex = mSettings->mMcastIface;
- int rc = setsockopt( mSettings->mSock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
- (char*) &mreq, sizeof(mreq));
- WARN_errno( rc == SOCKET_ERROR, "multicast join" );
+ if (setsockopt(mSettings->mSock, IPPROTO_IP,
+ IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+ die("IPv4 multicast join failed: did you use -j/-J?");
}
-#endif
-#endif
}
-// end McastJoin
/* -------------------------------------------------------------------
* Sets the Multicast TTL for outgoing packets.
* until a new connection arrives.
* ------------------------------------------------------------------- */
-void Listener::Accept( thread_Settings *server ) {
+void Listener::Accept( thread_Settings *server )
+{
+ socklen_t socklen = sizeof(server->peer);
- server->size_peer = sizeof(iperf_sockaddr);
- if ( isUDP( server ) ) {
+ if ( isConnectionLess( server ) ) {
/* -------------------------------------------------------------------
- * Do the equivalent of an accept() call for UDP sockets. This waits
- * on a listening UDP socket until we get a datagram.
+ * Do the equivalent of an accept() call for connection-less sockets.
+ * This waits on a listening datagram socket until we get a datagram.
* ------------------------------------------------------------------- */
int rc;
Iperf_ListEntry *exist;
int32_t datagramID;
+
server->mSock = INVALID_SOCKET;
while ( server->mSock == INVALID_SOCKET ) {
rc = recvfrom( mSettings->mSock, mBuf, mSettings->mBufLen, 0,
- (struct sockaddr*) &server->peer, &server->size_peer );
+ (struct sockaddr *)&server->peer, &socklen );
FAIL_errno( rc == SOCKET_ERROR, "recvfrom", mSettings );
Mutex_Lock( &clients_mutex );
- // Handle connection for UDP sockets.
+ // Handle connection for datagram-based sockets.
exist = Iperf_present( &server->peer, clients);
- datagramID = ntohl( ((UDP_datagram*) mBuf)->id );
+ datagramID = ntohl( ((dgram_record*) mBuf)->id );
if ( exist == NULL && datagramID >= 0 ) {
server->mSock = mSettings->mSock;
- int rc = connect( server->mSock, (struct sockaddr*) &server->peer,
- server->size_peer );
- FAIL_errno( rc == SOCKET_ERROR, "connect UDP", mSettings );
+ int rc = connect(server->mSock, (struct sockaddr *)&server->peer, socklen);
+ FAIL_errno( rc == SOCKET_ERROR, "datagram-based connect", mSettings );
} else {
server->mSock = INVALID_SOCKET;
}
}
} else {
// Handles interupted accepts. Returns the newly connected socket.
- server->mSock = INVALID_SOCKET;
-
- while ( server->mSock == INVALID_SOCKET ) {
- // accept a connection
- server->mSock = accept( mSettings->mSock,
- (sockaddr*) &server->peer, &server->size_peer );
- if ( server->mSock == INVALID_SOCKET && errno == EINTR ) {
- continue;
- }
- }
+ do {
+ server->mSock = accept(mSettings->mSock, (struct sockaddr *)&server->peer, &socklen);
+ } while (server->mSock == INVALID_SOCKET);
}
- server->size_local = sizeof(iperf_sockaddr);
- getsockname( server->mSock, (sockaddr*) &server->local,
- &server->size_local );
-} // end Accept
+ // find out which local interface the connection uses
+ socklen = sizeof(server->local);
+ getsockname(server->mSock, (struct sockaddr *)&server->local, &socklen);
+}
void Listener::UDPSingleServer( ) {
- bool client = false, UDP = isUDP( mSettings ), mCount = (mSettings->mThreads != 0);
+ bool client = (mSettings->mHost != NULL),
+ mCount = (mSettings->mThreads != 0);
thread_Settings *tempSettings = NULL;
Iperf_ListEntry *exist, *listtemp;
int rc;
int32_t datagramID;
- client_hdr* hdr = ( UDP ? (client_hdr*) (((UDP_datagram*)mBuf) + 1) :
- (client_hdr*) mBuf);
+ socklen_t socklen = sizeof(server->peer);
ReportStruct *reportstruct = new ReportStruct;
+ dgram_record *dgram_hdr = (dgram_record *)mBuf;
- if ( mSettings->mHost != NULL ) {
- client = true;
- SockAddr_remoteAddr( mSettings );
- }
+ assert( isPacketOriented( mSettings ) );
+
Settings_Copy( mSettings, &server );
server->mThreadMode = kMode_Server;
-
// Accept each packet,
// If there is no existing client, then start
// a new report to service the new client
do {
// Get next packet
while ( sInterupted == 0) {
- server->size_peer = sizeof( iperf_sockaddr );
- rc = recvfrom( mSettings->mSock, mBuf, mSettings->mBufLen, 0,
- (struct sockaddr*) &server->peer, &server->size_peer );
- WARN_errno( rc == SOCKET_ERROR, "recvfrom" );
- if ( rc == SOCKET_ERROR ) {
+ rc = recvfrom(mSettings->mSock, mBuf, mSettings->mBufLen, 0,
+ (struct sockaddr *)&server->peer, &socklen);
+ if (rc == SOCKET_ERROR) {
+ WARN_errno( 1, "recvfrom" );
return;
}
-
- // Handle connection for UDP sockets.
+ // Handle connection for datagram-based sockets.
exist = Iperf_present( &server->peer, clients);
- datagramID = ntohl( ((UDP_datagram*) mBuf)->id );
+ datagramID = ntohl( dgram_hdr->id );
if ( datagramID >= 0 ) {
if ( exist != NULL ) {
// read the datagram ID and sentTime out of the buffer
reportstruct->packetID = datagramID;
- reportstruct->sentTime.tv_sec = ntohl( ((UDP_datagram*) mBuf)->tv_sec );
- reportstruct->sentTime.tv_usec = ntohl( ((UDP_datagram*) mBuf)->tv_usec );
+ reportstruct->sentTime.tv_sec = ntohl( dgram_hdr->tv_sec );
+ reportstruct->sentTime.tv_usec = ntohl( dgram_hdr->tv_usec );
reportstruct->packetLen = rc;
gettimeofday( &(reportstruct->packetTime), NULL );
groupID--;
server->mSock = -groupID;
Mutex_Unlock( &groupCond );
- server->size_local = sizeof(iperf_sockaddr);
- getsockname( mSettings->mSock, (sockaddr*) &server->local,
- &server->size_local );
+ // make this a connected socket and determine local interface
+ connect(mSettings->mSock, (sockaddr *)&server->peer, socklen);
+ socklen = sizeof(server->local);
+ getsockname(mSettings->mSock, (sockaddr *)&server->local, &socklen);
break;
}
} else {
if ( exist != NULL ) {
// read the datagram ID and sentTime out of the buffer
reportstruct->packetID = -datagramID;
- reportstruct->sentTime.tv_sec = ntohl( ((UDP_datagram*) mBuf)->tv_sec );
- reportstruct->sentTime.tv_usec = ntohl( ((UDP_datagram*) mBuf)->tv_usec );
+ reportstruct->sentTime.tv_sec = ntohl( dgram_hdr->tv_sec );
+ reportstruct->sentTime.tv_usec = ntohl( dgram_hdr->tv_usec );
reportstruct->packetLen = rc;
gettimeofday( &(reportstruct->packetTime), NULL );
gettimeofday( &(reportstruct->packetTime), NULL );
CloseReport( exist->server->reporthdr, reportstruct );
- if ( rc > (int) ( sizeof( UDP_datagram )
- + sizeof( server_hdr ) ) ) {
- UDP_datagram *UDP_Hdr;
- server_hdr *hdr;
-
- UDP_Hdr = (UDP_datagram*) mBuf;
+ if ( rc > (int)(sizeof(dgram_record) + sizeof(server_hdr)) ) {
+ server_hdr *hdr = (server_hdr *)(dgram_hdr + 1);
Transfer_Info *stats = GetReport( exist->server->reporthdr );
- hdr = (server_hdr*) (UDP_Hdr+1);
hdr->flags = htonl( HEADER_VERSION1 );
hdr->total_len1 = htonl( (long) (stats->TotalLen >> 32) );
EndReport( exist->server->reporthdr );
exist->server->reporthdr = NULL;
Iperf_delete( &(exist->server->peer), &clients );
- } else if ( rc > (int) ( sizeof( UDP_datagram )
- + sizeof( server_hdr ) ) ) {
- UDP_datagram *UDP_Hdr;
- server_hdr *hdr;
-
- UDP_Hdr = (UDP_datagram*) mBuf;
- hdr = (server_hdr*) (UDP_Hdr+1);
+
+ } else if ( rc > (int)(sizeof(dgram_record) + sizeof(server_hdr)) ) {
+ server_hdr *hdr = (server_hdr *) (dgram_hdr + 1);
hdr->flags = htonl( 0 );
}
- sendto( mSettings->mSock, mBuf, mSettings->mBufLen, 0,
- (struct sockaddr*) &server->peer, server->size_peer);
+ if (write(mSettings->mSock, mBuf, mSettings->mBufLen) < 0)
+ WARN_errno(1, "UDPSingleServer write");
}
}
if ( server->mSock == INVALID_SOCKET ) {
}
// Reset Single Client Stuff
if ( isSingleClient( mSettings ) && clients == NULL ) {
- mSettings->peer = server->peer;
mClients--;
client = true;
// Once all the server threads exit then quit
mClients = 1;
}
}
- // Verify that it is allowed
- if ( client ) {
- if ( !SockAddr_Hostare_Equal( (sockaddr*) &mSettings->peer,
- (sockaddr*) &server->peer ) ) {
- // Not allowed try again
- connect( mSettings->mSock,
- (sockaddr*) &server->peer,
- server->size_peer );
- close( mSettings->mSock );
- mSettings->mSock = -1;
- Listen( );
- continue;
- }
- }
+ // Copy peer address (see note in Listener::Run())
+ if (client)
+ mSettings->peer = server->peer;
// Create an entry for the connection list
listtemp = new Iperf_ListEntry;
- memcpy(listtemp, &server->peer, sizeof(iperf_sockaddr));
+ memcpy(listtemp, &server->peer, sizeof(server->peer));
listtemp->server = server;
listtemp->next = NULL;
tempSettings = NULL;
if ( !isCompat( mSettings ) && !isMulticast( mSettings ) ) {
- Settings_GenerateClientSettings( server, &tempSettings,
- hdr );
+ client_hdr* hdr = (client_hdr *)(dgram_hdr + 1);
+
+ Settings_GenerateClientSettings(server, &tempSettings, hdr);
}