iperf: fix --daemon option
authorRafał Miłecki <rafal@milecki.pl>
Sun, 7 Oct 2018 12:17:50 +0000 (14:17 +0200)
committerRafał Miłecki <rafal@milecki.pl>
Sun, 7 Oct 2018 15:15:45 +0000 (17:15 +0200)
Support for -D got broken in the 2.0.11 release by the upstream commit
218d8c667944 ("first pass L2 mode w/UDP checks, v4 only"). After that
commit clients were still able to connect but no traffic was passed.
It was reported and is fixed now in the upstream git repository.

Backport two patches to fix this. The first one is just a requirement
for the later to apply. The second one is the real fix and it needed
only a small adjustment to apply without backporing the commit
10887b59c7e7 ("fix --txstart-time report messages").

Fixes: 7d15f96eaf76 ("iperf: bump to 2.0.12")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
(cherry picked from commit 87cd118794cc9375260ea213838e80ad5295e83c)

package/network/utils/iperf/Makefile
package/network/utils/iperf/patches/0001-fix-latent-bug-in-signal-handling-per-POSIX-calling-.patch [new file with mode: 0644]
package/network/utils/iperf/patches/0002-cleanup-main-startup-fix-daemon-mode-per-redirecting.patch [new file with mode: 0644]

index 3f7bfad9cc576a8b8f056149d256c061ab124488..6facf7bea792a8bf2f0a7baa03c1d64f6adcb181 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=iperf
 PKG_VERSION:=2.0.12
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
 PKG_HASH:=367f651fb1264b13f6518e41b8a7e08ce3e41b2a1c80e99ff0347561eed32646
diff --git a/package/network/utils/iperf/patches/0001-fix-latent-bug-in-signal-handling-per-POSIX-calling-.patch b/package/network/utils/iperf/patches/0001-fix-latent-bug-in-signal-handling-per-POSIX-calling-.patch
new file mode 100644 (file)
index 0000000..a713e06
--- /dev/null
@@ -0,0 +1,43 @@
+From 7c0ac64ebea38d0d9ff4d160db4d33bc087a3490 Mon Sep 17 00:00:00 2001
+From: Robert McMahon <rjmcmahon@rjmcmahon.com>
+Date: Mon, 16 Jul 2018 17:51:29 -0700
+Subject: [PATCH] fix latent bug in signal handling, per POSIX calling exit()
+ in signal handler is not safe.  Use _exit() instead.  Also, detect the user
+ signal SIGINT for the case of server needing two invocations to stop server
+ threads.  Note: the server threads still need some work from graceful
+ termination with a single ctrl-c
+
+---
+
+--- a/compat/signal.c
++++ b/compat/signal.c
+@@ -171,7 +171,7 @@ void sig_exit( int inSigno ) {
+     static int num = 0;
+     if ( num++ == 0 ) {
+         fflush( 0 );
+-        exit( 0 );
++      _exit(0);
+     }
+ } /* end sig_exit */
+--- a/src/main.cpp
++++ b/src/main.cpp
+@@ -268,7 +268,7 @@ void Sig_Interupt( int inSigno ) {
+     // We try to not allow a single interrupt handled by multiple threads
+     // to completely kill the app so we save off the first thread ID
+     // then that is the only thread that can supply the next interrupt
+-    if ( thread_equalid( sThread, thread_zeroid() ) ) {
++    if ( (inSigno == SIGINT) && thread_equalid( sThread, thread_zeroid() ) ) {
+         sThread = thread_getid();
+     } else if ( thread_equalid( sThread, thread_getid() ) ) {
+         sig_exit( inSigno );
+@@ -420,9 +420,3 @@ VOID ServiceStop() {
+ }
+ #endif
+-
+-
+-
+-
+-
+-
diff --git a/package/network/utils/iperf/patches/0002-cleanup-main-startup-fix-daemon-mode-per-redirecting.patch b/package/network/utils/iperf/patches/0002-cleanup-main-startup-fix-daemon-mode-per-redirecting.patch
new file mode 100644 (file)
index 0000000..c8655c9
--- /dev/null
@@ -0,0 +1,161 @@
+From 755be8bdb48d2536e39d2d7cf84e8a8f86b8776f Mon Sep 17 00:00:00 2001
+From: Robert McMahon <rjmcmahon@rjmcmahon.com>
+Date: Sat, 6 Oct 2018 13:36:52 -0700
+Subject: [PATCH] cleanup main startup, fix daemon mode per redirecting stdin,
+ stderr and stdout to /dev/null
+
+---
+
+--- a/src/main.cpp
++++ b/src/main.cpp
+@@ -167,67 +167,7 @@ int main( int argc, char **argv ) {
+     Settings_ParseCommandLine( argc, argv, ext_gSettings );
+     // Check for either having specified client or server
+-    if ( ext_gSettings->mThreadMode == kMode_Client
+-         || ext_gSettings->mThreadMode == kMode_Listener ) {
+-#ifdef WIN32
+-        // Start the server as a daemon
+-        if ( isDaemon( ext_gSettings )) {
+-          if (ext_gSettings->mThreadMode == kMode_Listener) {
+-              CmdInstallService(argc, argv);
+-          } else {
+-              fprintf(stderr, "Client cannot be run as a daemon\n");
+-          }
+-            return 0;
+-        }
+-
+-        // Remove the Windows service if requested
+-        if ( isRemoveService( ext_gSettings ) ) {
+-            // remove the service
+-            if ( CmdRemoveService() ) {
+-                fprintf(stderr, "IPerf Service is removed.\n");
+-                return 0;
+-            }
+-        }
+-#else
+-      if ( isDaemon( ext_gSettings ) ) {
+-          if (ext_gSettings->mThreadMode != kMode_Listener) {
+-              fprintf(stderr, "Iperf client cannot be run as a daemon\n");
+-              return 0;
+-          }
+-          if (daemon(1, 1) < 0) {
+-              perror("daemon");
+-          }
+-          fprintf( stderr, "Running Iperf Server as a daemon\n");
+-          fprintf( stderr, "The Iperf daemon process ID : %d\n",((int)getpid()));
+-          fclose(stdout);
+-          fclose(stderr);
+-          fclose(stdin);
+-      }
+-#endif
+-        // initialize client(s)
+-        if ( ext_gSettings->mThreadMode == kMode_Client ) {
+-            client_init( ext_gSettings );
+-        }
+-
+-#ifdef HAVE_THREAD
+-        // start up the reporter and client(s) or listener
+-        {
+-            thread_Settings *into = NULL;
+-            // Create the settings structure for the reporter thread
+-            Settings_Copy( ext_gSettings, &into );
+-            into->mThreadMode = kMode_Reporter;
+-
+-            // Have the reporter launch the client or listener
+-            into->runNow = ext_gSettings;
+-
+-            // Start all the threads that are ready to go
+-            thread_start( into );
+-        }
+-#else
+-        // No need to make a reporter thread because we don't have threads
+-        thread_start( ext_gSettings );
+-#endif
+-    } else {
++    if ((ext_gSettings->mThreadMode != kMode_Client) && (ext_gSettings->mThreadMode != kMode_Listener)) {
+         // neither server nor client mode was specified
+         // print usage and exit
+@@ -236,20 +176,75 @@ int main( int argc, char **argv ) {
+         // Starting in 2.0 to restart a previously defined service
+         // you must call iperf with "iperf -D" or using the environment variable
+         SERVICE_TABLE_ENTRY dispatchTable[] =
+-        {
+-            { (LPSTR)TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
+-            { NULL, NULL}
+-        };
++          {
++              { (LPSTR)TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
++              { NULL, NULL}
++          };
+       // starting the service by SCM, there is no arguments will be passed in.
+       // the arguments will pass into Service_Main entry.
+         if (!StartServiceCtrlDispatcher(dispatchTable) )
+             // If the service failed to start then print usage
+ #endif
+-        fprintf( stderr, usage_short, argv[0], argv[0] );
++          fprintf( stderr, usage_short, argv[0], argv[0] );
++      return 0;
++    }
++
++
++    switch (ext_gSettings->mThreadMode) {
++    case kMode_Client :
++      if ( isDaemon( ext_gSettings ) ) {
++          fprintf(stderr, "Iperf client cannot be run as a daemon\n");
++          return 0;
++      }
++        // initialize client(s)
++        client_init( ext_gSettings );
++      break;
++    case kMode_Listener :
++      if ( isDaemon( ext_gSettings ) ) {
++          fprintf( stderr, "Running Iperf Server as a daemon\n");
++          // Start the server as a daemon
++#ifdef WIN32
++          CmdInstallService(argc, argv);
++          // Remove the Windows service if requested
++          if ( isRemoveService( ext_gSettings ) ) {
++              // remove the service
++              if ( CmdRemoveService() ) {
++                  fprintf(stderr, "IPerf Service is removed.\n");
++                  return 0;
++              }
++          }
++#else
++          fflush(stderr);
++          // redirect stdin, stdout and sterr to /dev/null (see dameon and no close flag)
++          if (daemon(1, 0) < 0) {
++              perror("daemon");
++          }
++      }
++#endif
++      break;
++    default :
++      fprintf( stderr, "unknown mode");
++      break;
++    }
++#ifdef HAVE_THREAD
++        // start up the reporter and client(s) or listener
++    {
++      thread_Settings *into = NULL;
++      // Create the settings structure for the reporter thread
++      Settings_Copy( ext_gSettings, &into );
++      into->mThreadMode = kMode_Reporter;
++
++      // Have the reporter launch the client or listener
++      into->runNow = ext_gSettings;
+-        return 0;
++      // Start all the threads that are ready to go
++      thread_start( into );
+     }
++#else
++    // No need to make a reporter thread because we don't have threads
++    thread_start( ext_gSettings );
++#endif
+     // wait for other (client, server) threads to complete
+     thread_joinall();