/*--------------------------------------------------------------- * 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 * and Mark Gates * ------------------------------------------------------------------- */ #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