423 строки
15 KiB
C
423 строки
15 KiB
C
/*---------------------------------------------------------------
|
|
* Copyright (c) 1999,2000,2001,2002,2003
|
|
* The Board of Trustees of the University of Illinois
|
|
* All Rights Reserved.
|
|
*---------------------------------------------------------------
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software (Iperf) and associated
|
|
* documentation files (the "Software"), to deal in the Software
|
|
* without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute,
|
|
* sublicense, and/or sell copies of the Software, and to permit
|
|
* persons to whom the Software is furnished to do
|
|
* so, subject to the following conditions:
|
|
*
|
|
*
|
|
* Redistributions of source code must retain the above
|
|
* copyright notice, this list of conditions and
|
|
* the following disclaimers.
|
|
*
|
|
*
|
|
* Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimers in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
*
|
|
* Neither the names of the University of Illinois, NCSA,
|
|
* nor the names of its contributors may be used to endorse
|
|
* or promote products derived from this Software without
|
|
* specific prior written permission.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
* ________________________________________________________________
|
|
* National Laboratory for Applied Network Research
|
|
* National Center for Supercomputing Applications
|
|
* University of Illinois at Urbana-Champaign
|
|
* http://www.ncsa.uiuc.edu
|
|
* ________________________________________________________________
|
|
*
|
|
* Socket.cpp
|
|
* by Ajay Tirumala <tirumala@ncsa.uiuc.edu>
|
|
* and Mark Gates <mgates@nlanr.net>
|
|
* ------------------------------------------------------------------- */
|
|
|
|
#define HEADERS()
|
|
|
|
#include "headers.h"
|
|
|
|
#include "SocketAddr.h"
|
|
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
/* -------------------------------------------------------------------
|
|
* Create a socket address. If inHostname is not null, resolve that
|
|
* address and fill it in. Fill in the port number. Use IPv6 ADDR_ANY
|
|
* if that is what is desired.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void SockAddr_remoteAddr( thread_Settings *inSettings ) {
|
|
SockAddr_zeroAddress( &inSettings->peer );
|
|
if ( inSettings->mHost != NULL ) {
|
|
SockAddr_setHostname( inSettings->mHost, &inSettings->peer,
|
|
isIPV6( inSettings ) );
|
|
} else {
|
|
#ifdef HAVE_IPV6
|
|
if ( isIPV6( inSettings ) ) {
|
|
((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET6;
|
|
} else {
|
|
((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET;
|
|
}
|
|
}
|
|
|
|
if ( SockAddr_isIPv6( &inSettings->peer ) ) {
|
|
inSettings->size_peer = sizeof( struct sockaddr_in6 );
|
|
} else {
|
|
inSettings->size_peer = sizeof( struct sockaddr_in );
|
|
}
|
|
#else
|
|
((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET;
|
|
}
|
|
inSettings->size_peer = sizeof( struct sockaddr_in );
|
|
#endif
|
|
SockAddr_setPort( &inSettings->peer, inSettings->mPort );
|
|
}
|
|
// end SocketAddr
|
|
|
|
void SockAddr_localAddr( thread_Settings *inSettings ) {
|
|
SockAddr_zeroAddress( &inSettings->local );
|
|
if ( inSettings->mLocalhost != NULL ) {
|
|
SockAddr_setHostname( inSettings->mLocalhost, &inSettings->local,
|
|
isIPV6( inSettings ) );
|
|
} else {
|
|
#ifdef HAVE_IPV6
|
|
if ( isIPV6( inSettings ) ) {
|
|
((struct sockaddr*)&inSettings->local)->sa_family = AF_INET6;
|
|
} else {
|
|
((struct sockaddr*)&inSettings->local)->sa_family = AF_INET;
|
|
}
|
|
}
|
|
|
|
if ( SockAddr_isIPv6( &inSettings->local ) ) {
|
|
inSettings->size_local = sizeof( struct sockaddr_in6 );
|
|
} else {
|
|
inSettings->size_local = sizeof( struct sockaddr_in );
|
|
}
|
|
#else
|
|
((struct sockaddr*)&inSettings->local)->sa_family = AF_INET;
|
|
}
|
|
inSettings->size_local = sizeof( struct sockaddr_in );
|
|
#endif
|
|
SockAddr_setPort( &inSettings->local, inSettings->mPort );
|
|
}
|
|
// end SocketAddr
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Resolve the hostname address and fill it in.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void SockAddr_setHostname( const char* inHostname,
|
|
iperf_sockaddr *inSockAddr,
|
|
int isIPv6 ) {
|
|
|
|
// ..I think this works for both ipv6 & ipv4... we'll see
|
|
#if defined(HAVE_IPV6)
|
|
{
|
|
struct addrinfo *res, *itr;
|
|
int ret_ga;
|
|
|
|
ret_ga = getaddrinfo(inHostname, NULL, NULL, &res);
|
|
if ( ret_ga ) {
|
|
fprintf(stderr, "error: %s\n", gai_strerror(ret_ga));
|
|
exit(1);
|
|
}
|
|
if ( !res->ai_addr ) {
|
|
fprintf(stderr, "getaddrinfo failed to get an address... target was '%s'\n", inHostname);
|
|
exit(1);
|
|
}
|
|
|
|
// Check address type before filling in the address
|
|
// ai_family = PF_xxx; ai_protocol = IPPROTO_xxx, see netdb.h
|
|
// ...but AF_INET6 == PF_INET6
|
|
itr = res;
|
|
if ( isIPv6 ) {
|
|
// First check all results for a IPv6 Address
|
|
while ( itr != NULL ) {
|
|
if ( itr->ai_family == AF_INET6 ) {
|
|
memcpy(inSockAddr, (itr->ai_addr),
|
|
(itr->ai_addrlen));
|
|
freeaddrinfo(res);
|
|
return;
|
|
} else {
|
|
itr = itr->ai_next;
|
|
}
|
|
}
|
|
}
|
|
itr = res;
|
|
// Now find a IPv4 Address
|
|
while ( itr != NULL ) {
|
|
if ( itr->ai_family == AF_INET ) {
|
|
memcpy(inSockAddr, (itr->ai_addr),
|
|
(itr->ai_addrlen));
|
|
freeaddrinfo(res);
|
|
return;
|
|
} else {
|
|
itr = itr->ai_next;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
// first try just converting dotted decimal
|
|
// on Windows gethostbyname doesn't understand dotted decimal
|
|
int rc = inet_pton( AF_INET, inHostname,
|
|
(unsigned char*)&(((struct sockaddr_in*)inSockAddr)->sin_addr) );
|
|
inSockAddr->sin_family = AF_INET;
|
|
if ( rc == 0 ) {
|
|
struct hostent *hostP = gethostbyname( inHostname );
|
|
if ( hostP == NULL ) {
|
|
/* this is the same as herror() but works on more systems */
|
|
const char* format;
|
|
switch ( h_errno ) {
|
|
case HOST_NOT_FOUND:
|
|
format = "%s: Unknown host\n";
|
|
break;
|
|
case NO_ADDRESS:
|
|
format = "%s: No address associated with name\n";
|
|
break;
|
|
case NO_RECOVERY:
|
|
format = "%s: Unknown server error\n";
|
|
break;
|
|
case TRY_AGAIN:
|
|
format = "%s: Host name lookup failure\n";
|
|
break;
|
|
|
|
default:
|
|
format = "%s: Unknown resolver error\n";
|
|
break;
|
|
}
|
|
fprintf( stderr, format, inHostname );
|
|
exit(1);
|
|
|
|
return; // TODO throw
|
|
}
|
|
|
|
memcpy(&(((struct sockaddr_in*)inSockAddr)->sin_addr), *(hostP->h_addr_list),
|
|
(hostP->h_length));
|
|
}
|
|
#endif
|
|
}
|
|
// end setHostname
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Copy the IP address into the string.
|
|
* ------------------------------------------------------------------- */
|
|
void SockAddr_getHostAddress( iperf_sockaddr *inSockAddr, char* outAddress,
|
|
size_t len ) {
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET ) {
|
|
inet_ntop( AF_INET, &(((struct sockaddr_in*) inSockAddr)->sin_addr),
|
|
outAddress, len);
|
|
}
|
|
#ifdef HAVE_IPV6
|
|
else {
|
|
inet_ntop( AF_INET6, &(((struct sockaddr_in6*) inSockAddr)->sin6_addr),
|
|
outAddress, len);
|
|
}
|
|
#endif
|
|
}
|
|
// end getHostAddress
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Set the address to any (generally all zeros).
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void SockAddr_setAddressAny( iperf_sockaddr *inSockAddr ) {
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
|
|
memset( &(((struct sockaddr_in*) inSockAddr)->sin_addr), 0,
|
|
sizeof( struct in_addr ));
|
|
#if defined(HAVE_IPV6)
|
|
else
|
|
memset( &(((struct sockaddr_in6*) inSockAddr)->sin6_addr), 0,
|
|
sizeof( struct in6_addr ));
|
|
#endif
|
|
}
|
|
// end setAddressAny
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Set the port to the given port. Handles the byte swapping.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void SockAddr_setPort( iperf_sockaddr *inSockAddr, unsigned short inPort ) {
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
|
|
((struct sockaddr_in*) inSockAddr)->sin_port = htons( inPort );
|
|
#if defined(HAVE_IPV6)
|
|
else
|
|
((struct sockaddr_in6*) inSockAddr)->sin6_port = htons( inPort );
|
|
#endif
|
|
|
|
}
|
|
// end setPort
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Set the port to zero, which lets the OS pick the port.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void SockAddr_setPortAny( iperf_sockaddr *inSockAddr ) {
|
|
SockAddr_setPort( inSockAddr, 0 );
|
|
}
|
|
// end setPortAny
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Return the port. Handles the byte swapping.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
unsigned short SockAddr_getPort( iperf_sockaddr *inSockAddr ) {
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
|
|
return ntohs( ((struct sockaddr_in*) inSockAddr)->sin_port );
|
|
#if defined(HAVE_IPV6)
|
|
else
|
|
return ntohs( ((struct sockaddr_in6*) inSockAddr)->sin6_port);
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
// end getPort
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Return the IPv4 Internet Address from the sockaddr_in structure
|
|
* ------------------------------------------------------------------- */
|
|
|
|
struct in_addr* SockAddr_get_in_addr( iperf_sockaddr *inSockAddr ) {
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
|
|
return &(((struct sockaddr_in*) inSockAddr)->sin_addr);
|
|
|
|
fprintf(stderr, "FATAL: get_in_addr called on IPv6 address\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Return the IPv6 Internet Address from the sockaddr_in6 structure
|
|
* ------------------------------------------------------------------- */
|
|
#ifdef HAVE_IPV6
|
|
struct in6_addr* SockAddr_get_in6_addr( iperf_sockaddr *inSockAddr ) {
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 )
|
|
return &(((struct sockaddr_in6*) inSockAddr)->sin6_addr);
|
|
|
|
fprintf(stderr, "FATAL: get_in6_addr called on IPv4 address\n");
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Return the size of the appropriate address structure.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
Socklen_t SockAddr_get_sizeof_sockaddr( iperf_sockaddr *inSockAddr ) {
|
|
|
|
#if defined(HAVE_IPV6)
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 ) {
|
|
return(sizeof(struct sockaddr_in6));
|
|
}
|
|
#endif
|
|
return(sizeof(struct sockaddr_in));
|
|
}
|
|
// end get_sizeof_sockaddr
|
|
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Return if IPv6 socket
|
|
* ------------------------------------------------------------------- */
|
|
|
|
int SockAddr_isIPv6( iperf_sockaddr *inSockAddr ) {
|
|
|
|
#if defined(HAVE_IPV6)
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 ) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
// end get_sizeof_sockaddr
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Return true if the address is a IPv4 multicast address.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
int SockAddr_isMulticast( iperf_sockaddr *inSockAddr ) {
|
|
|
|
#if defined(HAVE_IPV6)
|
|
if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 ) {
|
|
return( IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6*) inSockAddr)->sin6_addr) ));
|
|
} else
|
|
#endif
|
|
{
|
|
// 224.0.0.0 to 239.255.255.255 (e0.00.00.00 to ef.ff.ff.ff)
|
|
const unsigned long kMulticast_Mask = 0xe0000000L;
|
|
|
|
return(kMulticast_Mask ==
|
|
(ntohl( ((struct sockaddr_in*) inSockAddr)->sin_addr.s_addr) & kMulticast_Mask));
|
|
}
|
|
}
|
|
// end isMulticast
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Zero out the address structure.
|
|
* ------------------------------------------------------------------- */
|
|
|
|
void SockAddr_zeroAddress( iperf_sockaddr *inSockAddr ) {
|
|
memset( inSockAddr, 0, sizeof( iperf_sockaddr ));
|
|
}
|
|
// zeroAddress
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Compare two sockaddrs and return true if they are equal
|
|
* ------------------------------------------------------------------- */
|
|
int SockAddr_are_Equal( struct sockaddr* first, struct sockaddr* second ) {
|
|
if ( first->sa_family == AF_INET && second->sa_family == AF_INET ) {
|
|
// compare IPv4 adresses
|
|
return( ((long) ((struct sockaddr_in*)first)->sin_addr.s_addr == (long) ((struct sockaddr_in*)second)->sin_addr.s_addr)
|
|
&& ( ((struct sockaddr_in*)first)->sin_port == ((struct sockaddr_in*)second)->sin_port) );
|
|
}
|
|
#if defined(HAVE_IPV6)
|
|
if ( first->sa_family == AF_INET6 && second->sa_family == AF_INET6 ) {
|
|
// compare IPv6 addresses
|
|
return( !memcmp(((struct sockaddr_in6*)first)->sin6_addr.s6_addr, ((struct sockaddr_in6*)second)->sin6_addr.s6_addr, sizeof(struct in6_addr))
|
|
&& (((struct sockaddr_in6*)first)->sin6_port == ((struct sockaddr_in6*)second)->sin6_port) );
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* -------------------------------------------------------------------
|
|
* Compare two sockaddrs and return true if the hosts are equal
|
|
* ------------------------------------------------------------------- */
|
|
int SockAddr_Hostare_Equal( struct sockaddr* first, struct sockaddr* second ) {
|
|
if ( first->sa_family == AF_INET && second->sa_family == AF_INET ) {
|
|
// compare IPv4 adresses
|
|
return( (long) ((struct sockaddr_in*)first)->sin_addr.s_addr ==
|
|
(long) ((struct sockaddr_in*)second)->sin_addr.s_addr);
|
|
}
|
|
#if defined(HAVE_IPV6)
|
|
if ( first->sa_family == AF_INET6 && second->sa_family == AF_INET6 ) {
|
|
// compare IPv6 addresses
|
|
return( !memcmp(((struct sockaddr_in6*)first)->sin6_addr.s6_addr,
|
|
((struct sockaddr_in6*)second)->sin6_addr.s6_addr, sizeof(struct in6_addr)));
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
}
|
|
#ifdef __cplusplus
|
|
} /* end extern "C" */
|
|
#endif
|