* List handling utilities to replace STD vector
*/
-struct Iperf_ListEntry;
-
/*
* A List entry that consists of a sockaddr
* a pointer to the Audience that sockaddr is
* entry
*/
struct Iperf_ListEntry {
- iperf_sockaddr data;
+ struct sockaddr_storage data;
MultiHeader *holder;
thread_Settings *server;
Iperf_ListEntry *next;
*/
void Iperf_pushback ( Iperf_ListEntry *add, Iperf_ListEntry **root );
-void Iperf_delete ( iperf_sockaddr *del, Iperf_ListEntry **root );
+void Iperf_delete ( struct sockaddr_storage *del, Iperf_ListEntry **root );
void Iperf_destroy ( Iperf_ListEntry **root );
-Iperf_ListEntry* Iperf_present ( iperf_sockaddr *find, Iperf_ListEntry *root );
+Iperf_ListEntry* Iperf_present ( struct sockaddr_storage *find, Iperf_ListEntry *root );
-Iperf_ListEntry* Iperf_hostpresent ( iperf_sockaddr *find, Iperf_ListEntry *root );
+Iperf_ListEntry* Iperf_hostpresent ( struct sockaddr_storage *find, Iperf_ListEntry *root );
#endif
} Transfer_Info;
typedef struct Connection_Info {
- iperf_sockaddr peer;
- Socklen_t size_peer;
- iperf_sockaddr local;
- Socklen_t size_local;
+ struct sockaddr_storage peer;
+ struct sockaddr_storage local;
} Connection_Info;
typedef struct ReporterData {
double lastTransit;
// shorts
unsigned short mPort; // -p
+ unsigned short mMcastIface; // -j or -J
// structs or miscellaneous
Transfer_Info info;
Connection_Info connection;
// int's
int mThreads; // -P
int mTOS; // -S
- int mSock;
+ int mSock; // socket descriptor
+ int mSockAF; // type of @mSock
int Extractor_size;
int mBufLen; // -l
int mMSS; // -M
// shorts
unsigned short mListenPort; // -L
unsigned short mPort; // -p
+ unsigned short mMcastIface; // -j or -J
// chars
char mFormat; // -f
- int mTTL; // -T
+ int mTTL; // -T
char pad1[2];
// structs or miscellaneous
- iperf_sockaddr peer;
- Socklen_t size_peer;
- iperf_sockaddr local;
- Socklen_t size_local;
+ struct sockaddr_storage peer; // remote part of socket
+ struct sockaddr_storage local; // local part of socket
nthread_t mTID;
} thread_Settings;
#include "headers.h"
#include "Settings.hpp"
+#include <net/if.h>
#ifdef __cplusplus
extern "C" {
#endif
-/* ------------------------------------------------------------------- */
- void SockAddr_localAddr( thread_Settings *inSettings );
- void SockAddr_remoteAddr( thread_Settings *inSettings );
- void SockAddr_setHostname( const char* inHostname,
- iperf_sockaddr *inSockAddr,
- int isIPv6 ); // DNS lookup
- void SockAddr_getHostname( iperf_sockaddr *inSockAddr,
- char* outHostname,
- size_t len ); // reverse DNS lookup
- void SockAddr_getHostAddress( iperf_sockaddr *inSockAddr,
- char* outAddress,
- size_t len ); // dotted decimal
+static inline bool SockAddr_isIPv6(const struct sockaddr_storage *ss)
+{
+ return ss->ss_family == AF_INET6;
+}
- void SockAddr_setPort( iperf_sockaddr *inSockAddr, unsigned short inPort );
- void SockAddr_setPortAny( iperf_sockaddr *inSockAddr );
- unsigned short SockAddr_getPort( iperf_sockaddr *inSockAddr );
+static inline int SockAddr_isMulticast(const struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET6)
+ return IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6 *)sa)->sin6_addr));
- void SockAddr_setAddressAny( iperf_sockaddr *inSockAddr );
+ // IPv4 multicast: 224.0.0.0 to 239.255.255.255 (e0.00.00.00 to ef.ff.ff.ff)
+ return sa->sa_family == AF_INET &&
+ (ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr) >> 28) == 0xe;
+}
- // return pointer to the struct in_addr
- struct in_addr* SockAddr_get_in_addr( iperf_sockaddr *inSockAddr );
-#ifdef HAVE_IPV6
- // return pointer to the struct in_addr
- struct in6_addr* SockAddr_get_in6_addr( iperf_sockaddr *inSockAddr );
-#endif
- // return the sizeof the addess structure (struct sockaddr_in)
- Socklen_t SockAddr_get_sizeof_sockaddr( iperf_sockaddr *inSockAddr );
-
- int SockAddr_isMulticast( iperf_sockaddr *inSockAddr );
-
- int SockAddr_isIPv6( iperf_sockaddr *inSockAddr );
+int SockAddr_Hostare_Equal(struct sockaddr_storage *first, struct sockaddr_storage *second);
+int SockAddr_are_Equal(struct sockaddr_storage *first, struct sockaddr_storage *second);
- int SockAddr_are_Equal( struct sockaddr *first, struct sockaddr *second );
- int SockAddr_Hostare_Equal( struct sockaddr *first, struct sockaddr *second );
+int SockAddr_port(struct sockaddr_storage *ss);
+const char *SockAddr_name(struct sockaddr_storage *ss, char *hbuf, size_t hbuflen);
- void SockAddr_zeroAddress( iperf_sockaddr *inSockAddr );
#ifdef __cplusplus
} /* end extern "C" */
#endif
#define INET_ADDRSTRLEN 15
#endif
-//#ifdef __cplusplus
- #ifdef HAVE_IPV6
- #define REPORT_ADDRLEN (INET6_ADDRSTRLEN + 1)
-typedef struct sockaddr_storage iperf_sockaddr;
- #else
- #define REPORT_ADDRLEN (INET_ADDRSTRLEN + 1)
-typedef struct sockaddr_in iperf_sockaddr;
- #endif
-//#endif
+// All addresses use struct sockaddr_storage, for compatibility with both v4/v6
+// The maximum report length is the maximum host name length for getnameinfo(3).
+#define REPORT_ADDRLEN (NI_MAXHOST + 1)
// Rationalize stdint definitions and sizeof, thanks to ac_create_stdint_h.m4
// from the gnu archive
ReportSettings( inSettings );
if ( mSettings->multihdr && isMultipleReport( inSettings ) ) {
mSettings->multihdr->report->connection.peer = mSettings->peer;
- mSettings->multihdr->report->connection.size_peer = mSettings->size_peer;
mSettings->multihdr->report->connection.local = mSettings->local;
- SockAddr_setPortAny( &mSettings->multihdr->report->connection.local );
- mSettings->multihdr->report->connection.size_local = mSettings->size_local;
}
}
* ------------------------------------------------------------------- */
void Client::Connect()
{
- int rc;
-
- assert( mSettings->inHostname != NULL );
-
- // The local socket needs to be filled in first, since the
- // IPv6 address testing for the peer depends on the type of
- // the local socket
- SockAddr_localAddr( mSettings );
- SockAddr_remoteAddr( mSettings );
- MakeSocket( mSettings);
- SetSocketOptions( mSettings );
-
- if ( mSettings->mLocalhost != NULL ) {
- // bind socket to local address
- rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local,
- SockAddr_get_sizeof_sockaddr( &mSettings->local ) );
- WARN_errno( rc == SOCKET_ERROR, "bind" );
- }
+ socklen_t size_local = sizeof(mSettings->local);
- // connect socket
- rc = connect( mSettings->mSock, (sockaddr*) &mSettings->peer,
- SockAddr_get_sizeof_sockaddr( &mSettings->peer ));
- WARN_errno( rc == SOCKET_ERROR, "connect" );
+ MakeSocket(mSettings);
- getsockname( mSettings->mSock, (sockaddr*) &mSettings->local,
- &mSettings->size_local );
- getpeername( mSettings->mSock, (sockaddr*) &mSettings->peer,
- &mSettings->size_peer );
+ /* determine local interface after establishing the connection */
+ getsockname(mSettings->mSock, (struct sockaddr *)&mSettings->local, &size_local);
/* The DCCP packet size must not exceed the MPS (RFC 4340, 14.) */
if (mSettings->mProtocol == kProto_DCCP) {
/*
* Delete Entry del from the List
*/
-void Iperf_delete ( iperf_sockaddr *del, Iperf_ListEntry **root ) {
+void Iperf_delete (struct sockaddr_storage *del, Iperf_ListEntry **root)
+{
Iperf_ListEntry *temp = Iperf_present( del, *root );
if ( temp != NULL ) {
if ( temp == *root ) {
/*
* Check if the exact Entry find is present
*/
-Iperf_ListEntry* Iperf_present ( iperf_sockaddr *find, Iperf_ListEntry *root ) {
- Iperf_ListEntry *itr = root;
- while ( itr != NULL ) {
- if ( SockAddr_are_Equal( (sockaddr*)itr, (sockaddr*)find ) ) {
+Iperf_ListEntry* Iperf_present(struct sockaddr_storage *find, Iperf_ListEntry *root)
+{
+ Iperf_ListEntry *itr;
+
+ for (itr = root; itr != NULL; itr = itr->next)
+ if (SockAddr_are_Equal(find, &itr->data))
return itr;
- }
- itr = itr->next;
- }
return NULL;
}
* Check if a Entry find is in the List or if any
* Entry exists that has the same host as the
* Entry find
+ * FIXME: The `or' condition was not implemented
*/
-Iperf_ListEntry* Iperf_hostpresent ( iperf_sockaddr *find, Iperf_ListEntry *root ) {
- Iperf_ListEntry *itr = root;
- while ( itr != NULL ) {
- if ( SockAddr_Hostare_Equal( (sockaddr*)itr, (sockaddr*)find ) ) {
- return itr;
- }
- itr = itr->next;
- }
- return NULL;
+Iperf_ListEntry* Iperf_hostpresent(struct sockaddr_storage *find, Iperf_ListEntry *root)
+{
+ return Iperf_present(find, root);
}
UDPSingleServer();
#endif
} else {
- bool client = false,
+ bool client = (mSettings->mHost != NULL),
mCount = (mSettings->mThreads != 0);
thread_Settings *tempSettings = NULL;
Iperf_ListEntry *exist, *listtemp;
client_hdr* hdr;
-
- if ( mSettings->mHost != NULL ) {
- client = true;
- SockAddr_remoteAddr( mSettings );
- }
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 ( isConnectionLess( 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
* ------------------------------------------------------------------- */
void Listener::Listen()
{
- int rc;
- int boolean = 1;
- Socklen_t len = sizeof(boolean);
-
- SockAddr_localAddr( mSettings );
- MakeSocket( mSettings );
-
- SetSocketOptions( mSettings );
-
- // reuse the address, so we can run if a former server was killed off
- setsockopt( mSettings->mSock, SOL_SOCKET, SO_REUSEADDR, (char*) &boolean, len );
-
- // listen for connections (TCP/DCCP only).
- rc = bind( mSettings->mSock, (sockaddr*) &mSettings->local, mSettings->size_local );
- WARN_errno( rc == SOCKET_ERROR, "bind" );
+ MakeSocket(mSettings);
// default backlog traditionally 5
- if ( !isConnectionLess( 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;
- mreq.ipv6mr_interface = 0;
+ memset(&mreq, 0, sizeof(mreq));
+ memcpy(&mreq.imr_multiaddr, &((struct sockaddr_in*)&mSettings->local)->sin_addr,
+ sizeof(mreq.imr_multiaddr));
+
+ 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.
void Listener::Accept( thread_Settings *server )
{
- server->size_peer = sizeof(iperf_sockaddr);
+ socklen_t socklen = sizeof(server->peer);
if ( isConnectionLess( server ) ) {
/* -------------------------------------------------------------------
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 );
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 );
+ 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, 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;
+ socklen_t socklen = sizeof(server->peer);
ReportStruct *reportstruct = new ReportStruct;
dgram_record *dgram_hdr = (dgram_record *)mBuf;
-
assert( isPacketOriented( mSettings ) );
- if ( mSettings->mHost != NULL ) {
- client = true;
- SockAddr_remoteAddr( 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 datagram-based sockets.
exist = Iperf_present( &server->peer, clients);
datagramID = ntohl( dgram_hdr->id );
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 {
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;
"Setting multicast TTL to %d\n";
const char join_multicast[] =
-"Joining multicast group %s\n";
+"Joining multicast group %s on %s\n";
const char client_datagram_size[] =
"Sending %d byte datagrams\n";
#include "SocketAddr.h"
#include "util.h"
-// create an internet socket
-void MakeSocket(thread_Settings *inSettings)
-{
- int type = 0, proto = 0, domain =
- SockAddr_isIPv6(&inSettings->local) ? AF_INET6 :
- AF_INET;
-
- switch (inSettings->mProtocol) {
- case kProto_TCP: type = SOCK_STREAM; break;
- case kProto_UDP: type = SOCK_DGRAM; break;
- case kProto_DCCP: type = SOCK_DCCP; break;
- }
- inSettings->mSock = socket( domain, type, proto );
-
- WARN_errno( inSettings->mSock == INVALID_SOCKET, "socket" );
-}
-
/* -------------------------------------------------------------------
* Set socket options before the listen() or connect() calls.
* These are optional performance tuning factors.
Socklen_t len = sizeof(int);
// check if we're sending multicast, and set TTL
- if ( isMulticast( inSettings ) && ( inSettings->mTTL > 0 ) ) {
+ if (isMulticast(inSettings) && inSettings->mTTL > 0) {
val = inSettings->mTTL;
-#ifdef HAVE_MULTICAST
- if ( !SockAddr_isIPv6( &inSettings->local ) ) {
- rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL,
- &val, len);
+ if (SockAddr_isIPv6(&inSettings->local))
+ rc = setsockopt(inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &val, len);
+ else
+ rc = setsockopt(inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL,
+ &val, len);
- WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
- }
-#ifdef HAVE_IPV6_MULTICAST
- else {
- rc = setsockopt( inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
- &val, len);
- WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
- }
-#endif /* IPV6_MULTICAST */
-#endif /* MULTICAST */
+ WARN_errno( rc == SOCKET_ERROR, "multicast ttl" );
}
&val, len );
WARN_errno( rc == SOCKET_ERROR, "setsockopt DCCP_SOCKOPT_SERVICE" );
}
+
+ // reuse the address, so we can run if a former server was killed off
+ if (inSettings->mThreadMode == kMode_Listener) {
+ val = 1;
+ rc = setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEADDR, &val, len);
+ WARN_errno( rc == SOCKET_ERROR, "setsockopt SO_REUSEADDR" );
+ }
+}
+
+void MakeSocket(thread_Settings *inSettings)
+{
+ struct addrinfo *local = NULL, *src,
+ *remote = NULL, *dst, hints;
+ char port[6];
+ int rc, socktype = sockType(inSettings->mProtocol);
+
+ assert(inSettings->mLocalhost || inSettings->mHost);
+
+ memset(&inSettings->local, 0, sizeof(inSettings->local));
+ memset(&inSettings->peer, 0, sizeof(inSettings->peer));
+ sprintf(port, "%u", inSettings->mPort);
+
+ /*
+ * Set up address hint structure
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = inSettings->mSockAF;
+ hints.ai_socktype = socktype;
+ /*
+ * CHEAT: getaddrinfo does not support SOCK_DCCP and using a zero
+ * ai_socktype will return IPv4 addresses first (which is bad on
+ * a dual-stack host). Pretend here to be UDP - this usually works.
+ */
+ if (inSettings->mProtocol == IPPROTO_DCCP)
+ hints.ai_socktype = SOCK_DGRAM;
+
+ /* only use addresses available on the host */
+ hints.ai_flags = AI_ADDRCONFIG;
+ if (inSettings->mSockAF == AF_INET6)
+ /* use v4-mapped-v6 if no v6 addresses found */
+ hints.ai_flags |= AI_V4MAPPED | AI_ALL;
+
+ /*
+ * Obtain local/remote address information
+ */
+ if (inSettings->mLocalhost || inSettings->mThreadMode == kMode_Listener) {
+ if (inSettings->mLocalhost == NULL)
+ hints.ai_flags |= AI_PASSIVE;
+ if ((rc = getaddrinfo(inSettings->mLocalhost, port, &hints, &local)))
+ die("Can not resolve local address %s#%s: %s",
+ inSettings->mLocalhost ? : "(local)", port, gai_strerror(rc));
+ }
+
+ if (inSettings->mHost && inSettings->mThreadMode != kMode_Listener) {
+ if ((rc = getaddrinfo(inSettings->mHost, port, &hints, &remote)))
+ die("Can not resolve peer address %s#%s: %s",
+ inSettings->mHost, port, gai_strerror(rc));
+ }
+
+ /*
+ * Iterate over all src/dst combination, exhausting dst first
+ */
+ for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) {
+ if (src && src->ai_family == AF_INET &&
+ dst && dst->ai_family == AF_INET6)
+ goto get_next_dst; /* v4 -> v6 is not possible */
+
+ inSettings->mSockAF = src ? src->ai_family : dst->ai_family;
+ inSettings->mSock = socket(inSettings->mSockAF, socktype,
+ inSettings->mProtocol);
+ if (inSettings->mSock < 0)
+ goto get_next_dst;
+
+ SetSocketOptions(inSettings);
+
+ if (src) {
+ if (bind(inSettings->mSock, src->ai_addr, src->ai_addrlen) < 0) {
+ close(inSettings->mSock);
+ goto get_next_src;
+ }
+ if (!dst)
+ break; /* bind-only completed successfully */
+ }
+
+ if (dst && connect(inSettings->mSock, dst->ai_addr, dst->ai_addrlen) == 0)
+ break; /* connection completed successfully */
+ close(inSettings->mSock);
+get_next_dst:
+ if (dst && (dst = dst->ai_next))
+ continue;
+get_next_src:
+ if (src && (src = src->ai_next))
+ dst = remote; /* restart inner loop */
+ }
+
+ if (src == NULL && dst == NULL)
+ die("Can not create %s socket", protoName(inSettings->mProtocol));
+ if (src) {
+ if (SockAddr_isMulticast(src->ai_addr))
+ setMulticast(inSettings);
+ memcpy(&inSettings->local, src->ai_addr, src->ai_addrlen);
+ }
+ if (dst) {
+ if (SockAddr_isMulticast(dst->ai_addr))
+ setMulticast(inSettings);
+ memcpy(&inSettings->peer, dst->ai_addr, dst->ai_addrlen);
+ }
+
+ if (local)
+ freeaddrinfo(local);
+ if (remote)
+ freeaddrinfo(remote);
+
+ if (isMulticast(inSettings) && !isConnectionLess(inSettings))
+ die("Can not use %s with multicast.", protoName(inSettings->mProtocol));
}
}
}
-void *CSV_peer( Connection_Info *stats, int ID ) {
-
- // copy the inet_ntop into temp buffers, to avoid overwriting
- char local_addr[ REPORT_ADDRLEN ];
- char remote_addr[ REPORT_ADDRLEN ];
- char *buf = malloc( REPORT_ADDRLEN*2 + 10 );
- struct sockaddr *local = ((struct sockaddr*)&stats->local);
- struct sockaddr *peer = ((struct sockaddr*)&stats->peer);
+void *CSV_peer(Connection_Info *stats, int ID)
+{
+ char laddr[REPORT_ADDRLEN],
+ daddr[REPORT_ADDRLEN],
+ *buf = malloc(2 * REPORT_ADDRLEN + 10);
+ unsigned lport = SockAddr_port(&stats->local),
+ dport = SockAddr_port(&stats->peer);
- if ( local->sa_family == AF_INET ) {
- inet_ntop( AF_INET, &((struct sockaddr_in*)local)->sin_addr,
- local_addr, REPORT_ADDRLEN);
- }
-#ifdef HAVE_IPV6
- else {
- inet_ntop( AF_INET6, &((struct sockaddr_in6*)local)->sin6_addr,
- local_addr, REPORT_ADDRLEN);
- }
-#endif
-
- if ( peer->sa_family == AF_INET ) {
- inet_ntop( AF_INET, &((struct sockaddr_in*)peer)->sin_addr,
- remote_addr, REPORT_ADDRLEN);
- }
-#ifdef HAVE_IPV6
- else {
- inet_ntop( AF_INET6, &((struct sockaddr_in6*)peer)->sin6_addr,
- remote_addr, REPORT_ADDRLEN);
- }
-#endif
+ SockAddr_name(&stats->local, laddr, sizeof(laddr));
+ SockAddr_name(&stats->peer, daddr, sizeof(daddr));
- snprintf(buf, REPORT_ADDRLEN*2+10, reportCSV_peer,
- local_addr, ( local->sa_family == AF_INET ?
- ntohs(((struct sockaddr_in*)local)->sin_port) :
-#ifdef HAVE_IPV6
- ntohs(((struct sockaddr_in6*)local)->sin6_port)),
-#else
- 0),
-#endif
- remote_addr, ( peer->sa_family == AF_INET ?
- ntohs(((struct sockaddr_in*)peer)->sin_port) :
-#ifdef HAVE_IPV6
- ntohs(((struct sockaddr_in6*)peer)->sin6_port)));
-#else
- 0));
-#endif
+ snprintf(buf, 2 * REPORT_ADDRLEN, reportCSV_peer,
+ laddr, lport, daddr, dport);
return buf;
}
reporter_printstats( stats );
}
+static char *McastIface(const unsigned if_index)
+{
+ static char ifnam[IF_NAMESIZE];
+
+ if (!if_index)
+ return "default interface";
+ if (if_indextoname(if_index, ifnam))
+ return ifnam;
+ return "unknown interface";
+}
+
/*
* Report the client or listener Settings in default style
*/
data->mPort );
}
if ( data->mLocalhost != NULL ) {
- printf( bind_address, data->mLocalhost );
- if ( SockAddr_isMulticast( &data->connection.local ) ) {
- printf( join_multicast, data->mLocalhost );
- }
+ if (SockAddr_isMulticast((struct sockaddr *)&data->connection.local))
+ printf(join_multicast, data->mLocalhost, McastIface(data->mMcastIface));
+ else
+ printf(bind_address, data->mLocalhost);
}
if ( isPacketOriented( data ) ) {
printf( (data->mThreadMode == kMode_Listener ?
server_datagram_size : client_datagram_size),
data->mBufLen );
- if ( SockAddr_isMulticast( &data->connection.peer ) ) {
+ if (SockAddr_isMulticast((struct sockaddr *)&data->connection.peer))
printf( multicast_ttl, data->info.mTTL);
- }
} else if (data->mProtocol == kProto_DCCP)
printf("NOTE: running in bytestream-mode (maximum speed)\n");
/*
* Report a socket's peer IP address in default style
*/
-void *reporter_reportpeer( Connection_Info *stats, int ID ) {
- if ( ID > 0 ) {
- // copy the inet_ntop into temp buffers, to avoid overwriting
- char local_addr[ REPORT_ADDRLEN ];
- char remote_addr[ REPORT_ADDRLEN ];
- struct sockaddr *local = ((struct sockaddr*)&stats->local);
- struct sockaddr *peer = ((struct sockaddr*)&stats->peer);
-
- if ( local->sa_family == AF_INET ) {
- inet_ntop( AF_INET, &((struct sockaddr_in*)local)->sin_addr,
- local_addr, REPORT_ADDRLEN);
- }
-#ifdef HAVE_IPV6
- else {
- inet_ntop( AF_INET6, &((struct sockaddr_in6*)local)->sin6_addr,
- local_addr, REPORT_ADDRLEN);
- }
-#endif
-
- if ( peer->sa_family == AF_INET ) {
- inet_ntop( AF_INET, &((struct sockaddr_in*)peer)->sin_addr,
- remote_addr, REPORT_ADDRLEN);
- }
-#ifdef HAVE_IPV6
- else {
- inet_ntop( AF_INET6, &((struct sockaddr_in6*)peer)->sin6_addr,
- remote_addr, REPORT_ADDRLEN);
- }
-#endif
-
- printf( report_peer,
- ID,
- local_addr, ( local->sa_family == AF_INET ?
- ntohs(((struct sockaddr_in*)local)->sin_port) :
-#ifdef HAVE_IPV6
- ntohs(((struct sockaddr_in6*)local)->sin6_port)),
-#else
- 0),
-#endif
- remote_addr, ( peer->sa_family == AF_INET ?
- ntohs(((struct sockaddr_in*)peer)->sin_port) :
-#ifdef HAVE_IPV6
- ntohs(((struct sockaddr_in6*)peer)->sin6_port)));
-#else
- 0));
-#endif
+void *reporter_reportpeer(Connection_Info *stats, int ID)
+{
+ if (ID > 0) {
+ char laddr[REPORT_ADDRLEN],
+ daddr[REPORT_ADDRLEN];
+ unsigned lport = SockAddr_port(&stats->local),
+ dport = SockAddr_port(&stats->peer);
+
+ SockAddr_name(&stats->local, laddr, sizeof(laddr));
+ SockAddr_name(&stats->peer, daddr, sizeof(daddr));
+ printf(report_peer, ID, laddr, lport, daddr, dport);
}
return NULL;
}
-// end ReportPeer
/* -------------------------------------------------------------------
* Report the MSS and MTU, given the MSS (or a guess thereof)
if ( isConnectionReport( agent ) ) {
data->type |= CONNECTION_REPORT;
data->connection.peer = agent->peer;
- data->connection.size_peer = agent->size_peer;
- SockAddr_setPortAny( &data->connection.peer );
data->connection.local = agent->local;
- data->connection.size_local = agent->size_local;
- SockAddr_setPortAny( &data->connection.local );
}
}
} else {
if ( reporthdr != NULL ) {
data->type |= CONNECTION_REPORT;
data->connection.peer = agent->peer;
- data->connection.size_peer = agent->size_peer;
data->connection.local = agent->local;
- data->connection.size_local = agent->size_local;
} else {
FAIL(1, "Out of Memory!!\n", agent);
}
data->mProtocol = agent->mProtocol;
data->mThreadMode = agent->mThreadMode;
data->mPort = agent->mPort;
+ data->mMcastIface = agent->mMcastIface;
data->info.mFormat = agent->mFormat;
data->info.mTTL = agent->mTTL;
data->connection.peer = agent->peer;
- data->connection.size_peer = agent->size_peer;
data->connection.local = agent->local;
- data->connection.size_local = agent->size_local;
#ifdef HAVE_THREAD
/*
stats->cntDatagrams = ntohl( server->datagrams );
stats->mUDP = (char)kMode_Server;
reporthdr->report.connection.peer = agent->local;
- reporthdr->report.connection.size_peer = agent->size_local;
reporthdr->report.connection.local = agent->peer;
- reporthdr->report.connection.size_local = agent->size_peer;
#ifdef HAVE_THREAD
/*
{"format", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"interval", required_argument, NULL, 'i'},
+{"mcast_iface",required_argument, NULL, 'j'},
{"len", required_argument, NULL, 'l'},
{"print_mss", no_argument, NULL, 'm'},
{"num", required_argument, NULL, 'n'},
{"IPERF_FORMAT", required_argument, NULL, 'f'},
// skip help
{"IPERF_INTERVAL", required_argument, NULL, 'i'},
+{"IPERF_MCASTIFACE", required_argument, NULL, 'j'},
{"IPERF_LEN", required_argument, NULL, 'l'},
{"IPERF_PRINT_MSS", no_argument, NULL, 'm'},
{"IPERF_NUM", required_argument, NULL, 'n'},
#define SHORT_OPTIONS()
const char short_options[] =
- "12b::c:df:hi:l:mn:o:p:rst:uvw:x:y:B:CDF:IL:M:NP:RS:T:UVW";
+ "12b::c:df:hi:j:l:mn:o:p:rst:uvw:x:y:B:CDF:IJ:L:M:NP:RS:T:UV:W";
/* -------------------------------------------------------------------
* defaults
// below.
memset( main, 0, sizeof(thread_Settings) );
main->mSock = INVALID_SOCKET;
+ //main->mSockAF = AF_UNSPEC
main->mReportMode = kReport_Default;
// option, defaults
main->flags = FLAG_MODETIME | FLAG_STDOUT; // Default time and stdout
//main->mFileInput = false; // -F,
//main->mFileName = NULL; // -F, filename
//main->mStdin = false; // -I, default not stdin
+ //main->mMcastIface = 0; // -J, default: host chooses interface
//main->mListenPort = 0; // -L, listen port
//main->mMSS = 0; // -M, ie. don't set MSS
//main->mNodelay = false; // -N, don't set nodelay
strcpy( mExtSettings->mHost, optarg );
if ( mExtSettings->mThreadMode == kMode_Unknown ) {
- // Test for Multicast
- iperf_sockaddr temp;
- SockAddr_setHostname( mExtSettings->mHost, &temp,
- (isIPV6( mExtSettings ) ? 1 : 0 ));
- if ( SockAddr_isMulticast( &temp ) ) {
- setMulticast( mExtSettings );
- }
mExtSettings->mThreadMode = kMode_Client;
mExtSettings->mThreads = 1;
}
}
break;
+ case 'j':
+ case 'J': // multicast interface to join multicast address on
+ mExtSettings->mMcastIface = if_nametoindex(optarg);
+ if (!mExtSettings->mMcastIface)
+ die("Interface \"%s\" does not work for -j/-J.", optarg);
+ break;
+
case 'l': // length of each buffer
Settings_GetUpperCaseArg(optarg,outarg);
mExtSettings->mBufLen = byte_atoi( outarg );
case 'B': // specify bind address
mExtSettings->mLocalhost = new char[ strlen( optarg ) + 1 ];
strcpy( mExtSettings->mLocalhost, optarg );
- // Test for Multicast
- iperf_sockaddr temp;
- SockAddr_setHostname( mExtSettings->mLocalhost, &temp,
- (isIPV6( mExtSettings ) ? 1 : 0 ));
- if ( SockAddr_isMulticast( &temp ) ) {
- setMulticast( mExtSettings );
- }
break;
case 'C': // Run in Compatibility Mode
mExtSettings->mTTL = atoi( optarg );
break;
+ case 'V': // IP Domain: the optional ar
+ mExtSettings->mSockAF = AF_INET6;
+ if ( optarg && optarg[0] == '4' )
+ mExtSettings->mSockAF = AF_INET;
+ break;
case 'U': // single threaded UDP server
setSingleUDP( mExtSettings );
break;
- case 'V': // IPv6 Domain
- setIPV6( mExtSettings );
- if ( mExtSettings->mThreadMode == kMode_Server
- && mExtSettings->mLocalhost != NULL ) {
- // Test for Multicast
- iperf_sockaddr temp;
- SockAddr_setHostname( mExtSettings->mLocalhost, &temp, 1);
- if ( SockAddr_isMulticast( &temp ) ) {
- setMulticast( mExtSettings );
- }
- } else if ( mExtSettings->mThreadMode == kMode_Client ) {
- // Test for Multicast
- iperf_sockaddr temp;
- SockAddr_setHostname( mExtSettings->mHost, &temp, 1 );
- if ( SockAddr_isMulticast( &temp ) ) {
- setMulticast( mExtSettings );
- }
- }
- break;
-
case 'W' :
setSuggestWin( mExtSettings );
fprintf( stderr, "The -W option is not available in this release\n");
strcpy( (*client)->mLocalhost, server->mLocalhost );
}
(*client)->mHost = new char[REPORT_ADDRLEN];
- if ( ((sockaddr*)&server->peer)->sa_family == AF_INET ) {
- inet_ntop( AF_INET, &((sockaddr_in*)&server->peer)->sin_addr,
- (*client)->mHost, REPORT_ADDRLEN);
- }
-#ifdef HAVE_IPV6
- else {
- inet_ntop( AF_INET6, &((sockaddr_in6*)&server->peer)->sin6_addr,
- (*client)->mHost, REPORT_ADDRLEN);
- }
-#endif
+ SockAddr_name(&server->peer, (*client)->mHost, REPORT_ADDRLEN);
} else {
*client = NULL;
}
#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