]> sjero.net Git - iperf/blobdiff - src/Listener.cpp
Native IPv6 support for iperf
[iperf] / src / Listener.cpp
index 1cc0de944c232a316954cf712e78c36e95f2693b..8afd6aa12c58707716a53a2e04d2b382e09a7f92 100644 (file)
@@ -128,21 +128,15 @@ void Listener::Run(void)
         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 
@@ -158,9 +152,9 @@ void Listener::Run(void)
                 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
@@ -171,23 +165,16 @@ void Listener::Run(void)
                     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
@@ -270,69 +257,50 @@ void Listener::Run(void)
  * ------------------------------------------------------------------- */
 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.
@@ -363,7 +331,7 @@ void Listener::McastSetTTL( int val ) {
 
 void Listener::Accept( thread_Settings *server )
 {
-    server->size_peer = sizeof(iperf_sockaddr); 
+    socklen_t socklen = sizeof(server->peer);
 
     if ( isConnectionLess( server ) ) {
         /* ------------------------------------------------------------------- 
@@ -377,7 +345,7 @@ void Listener::Accept( thread_Settings *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 );
@@ -387,8 +355,7 @@ void Listener::Accept( thread_Settings *server )
             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;
@@ -397,43 +364,32 @@ void Listener::Accept( thread_Settings *server )
         }
     } 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 
@@ -442,15 +398,13 @@ void Listener::UDPSingleServer( ) {
     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 );
@@ -470,9 +424,10 @@ void Listener::UDPSingleServer( ) {
                     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 {
@@ -516,8 +471,8 @@ void Listener::UDPSingleServer( ) {
                     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 ) {
@@ -529,7 +484,6 @@ void Listener::UDPSingleServer( ) {
         }
         // Reset Single Client Stuff
         if ( isSingleClient( mSettings ) && clients == NULL ) {
-            mSettings->peer = server->peer;
             mClients--;
             client = true;
             // Once all the server threads exit then quit
@@ -540,24 +494,13 @@ void Listener::UDPSingleServer( ) {
                 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;