| /*--------------------------------------------------------------- |
| * 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 |