X-Git-Url: http://sjero.net/git/?p=iperf;a=blobdiff_plain;f=src%2FSocketAddr.c;h=6e96e81a6d27261b91c25198314c46a7020f3409;hp=0278bdf935260ccb37cdf02526220bd8d4380f4b;hb=a5a03e6ab0fdf9c4d7d4c085fcf01436f9ba3202;hpb=90fc1e2c0c74319759b21d4a177c32691b88fdf3 diff --git a/src/SocketAddr.c b/src/SocketAddr.c index 0278bdf..6e96e81 100644 --- a/src/SocketAddr.c +++ b/src/SocketAddr.c @@ -59,364 +59,85 @@ #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 +/* return the port of @ss, -1 if undefined */ +int SockAddr_port(struct sockaddr_storage *ss) +{ + if (ss->ss_family == AF_INET) + return ntohs(((struct sockaddr_in *)ss)->sin_port); + else if (ss->ss_family == AF_INET6) + return ntohs(((struct sockaddr_in6 *)ss)->sin6_port); + return -1; } -// 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 ); + * Print socket name into output (must be INET6_ADDRSTRLEN long). + * This one works around the quirk of inet_ntop/getaddrinfo to represent + * print IPv4-mapped-IPv6 addresses as sockaddr_in6 (::FFFF:x.x.x.x). + * Make the #ifndef an `#ifdef' to disable this conversion. + * ------------------------------------------------------------------- */ +const char *SockAddr_name(struct sockaddr_storage *ss, char *hbuf, size_t hbuflen) +{ + int af = ss->ss_family; + const void *ptr; + + if (ss->ss_family == AF_INET) + ptr = &((struct sockaddr_in *)ss)->sin_addr; + else if (ss->ss_family == AF_INET6) { + const struct in6_addr *v6_addr; + + ptr = v6_addr = &((struct sockaddr_in6 *)ss)->sin6_addr; +#ifndef I_WANT_V4_MAPPED_IN_MY_OUTPUT + if (IN6_IS_ADDR_V4MAPPED(v6_addr)) { + struct in_addr ia; + + // extract the IPv4 address from the last 4 bytes + memcpy(&ia.s_addr, &v6_addr->s6_addr[12], 4); + ptr = &ia; + af = AF_INET; + } #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; + } else { + return NULL; // undetermined family (e.g. AF_UNSPEC) + } + return inet_ntop(af, ptr, hbuf, hbuflen); } -// 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)); - } +static int SockAddr_AF_are_Equal(struct sockaddr_storage *first, struct sockaddr_storage *second) +{ + return first->ss_family == second->ss_family; } -// end isMulticast /* ------------------------------------------------------------------- - * Zero out the address structure. + * Compare two sockaddrs and return true if the hosts are equal * ------------------------------------------------------------------- */ - -void SockAddr_zeroAddress( iperf_sockaddr *inSockAddr ) { - memset( inSockAddr, 0, sizeof( iperf_sockaddr )); +int SockAddr_Hostare_Equal(struct sockaddr_storage *first, struct sockaddr_storage *second) +{ + if (!SockAddr_AF_are_Equal(first, second)) + return 0; + if (first->ss_family == AF_INET) + return !memcmp(&((struct sockaddr_in *)first)->sin_addr, + &((struct sockaddr_in *)second)->sin_addr, sizeof(struct in_addr)); + if (first->ss_family == AF_INET6) + return !memcmp(&((struct sockaddr_in6 *)first)->sin6_addr, + &((struct sockaddr_in6 *)second)->sin6_addr, sizeof(struct in6_addr)); + return 0; } -// zeroAddress /* ------------------------------------------------------------------- - * Compare two sockaddrs and return true if they are equal + * Compare two socket structs 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; - +int SockAddr_are_Equal(struct sockaddr_storage *first, struct sockaddr_storage *second) +{ + if (!SockAddr_Hostare_Equal(first, second)) + return 0; + if (first->ss_family == AF_INET) + return ((struct sockaddr_in*)first)->sin_port == ((struct sockaddr_in*)second)->sin_port; + if (first->ss_family == AF_INET6) + return (((struct sockaddr_in6*)first)->sin6_port == ((struct sockaddr_in6*)second)->sin6_port); + 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