[netperf-dev] netperf4 commit notice r82 - branches/glib_migration/src

raj at netperf.org raj at netperf.org
Thu Mar 16 15:53:05 PST 2006


Author: raj
Date: 2006-03-16 15:53:04 -0800 (Thu, 16 Mar 2006)
New Revision: 82

Modified:
   branches/glib_migration/src/netperf.h
   branches/glib_migration/src/netserver.c
Log:
Start migrating the netserver to use the glib process spawning and 
eventloop constructs.


Modified: branches/glib_migration/src/netperf.h
===================================================================
--- branches/glib_migration/src/netperf.h	2006-03-16 21:16:57 UTC (rev 81)
+++ branches/glib_migration/src/netperf.h	2006-03-16 23:53:04 UTC (rev 82)
@@ -118,6 +118,7 @@
 #define NETPERF_DEBUG_LOG_SUFFIX  ".log"
 #define netperf_socklen_t socklen_t
 #define close(x) closesocket(x)
+#define CLOSE_SOCKET(x) closesocket(x)
 #define strcasecmp(a,b) _stricmp(a,b)
 #define getpid() ((int)GetCurrentProcessId())
 #else
@@ -127,6 +128,7 @@
 #define INVALID_SOCKET -1
 #define SOCKET_ERROR -1
 #define SOCKET int
+#define CLOSE_SOCKET(x) close(x)
 #endif
 
 #include "netconfidence.h"
@@ -135,7 +137,7 @@
 #define NETPERF_DTD_FILE (const xmlChar *)"http://www.netperf.org/netperf_docs.dtd/1.0"
 #define NETPERF_VERSION (const xmlChar *)"4"
 #define NETPERF_UPDATE  (const xmlChar *)"0"
-#define NETPERF_FIX     (const xmlChar *)"999"
+#define NETPERF_FIX     (const xmlChar *)"997"
 
 #define NETPERF_DEBUG_ENTRY(d,w) \
   if (d) { \

Modified: branches/glib_migration/src/netserver.c
===================================================================
--- branches/glib_migration/src/netserver.c	2006-03-16 21:16:57 UTC (rev 81)
+++ branches/glib_migration/src/netserver.c	2006-03-16 23:53:04 UTC (rev 82)
@@ -1,5 +1,5 @@
 char netserver_id[]="\
-@(#)netserver.c (c) Copyright 2005, Hewlett-Packard Company, $Id$";
+@(#)netserver.c (c) Copyright 2006, Hewlett-Packard Company, $Id$";
 /*
 
 This file is part of netperf4.
@@ -29,10 +29,6 @@
 but you are not obligated to do so.  If you do not wish to do so,
 delete this exception statement from your version.
 
-#include <termios.h>
-#include <grp.h>
-#include <pwd.h>
-
 */
 
 #ifdef HAVE_CONFIG_H
@@ -40,13 +36,9 @@
 #endif
 
 #ifdef WITH_GLIB
-# ifdef HAVE_GLIB_H
-#  include <glib.h>
-# endif 
+# include <glib.h>
 #else
-# ifdef HAVE_PTHREAD_H
-#  include <pthread.h>
-# endif
+# error sorry, this netserver requires glib
 #endif
 
 #ifdef HAVE_STDIO_H
@@ -140,38 +132,328 @@
 int        want_quiet;                                  /* --quiet, --silent */
 int        want_brief;                                  /* --brief */
 int        want_verbose;                                /* --verbose */
+gboolean   spawn_on_accept = TRUE;
+gboolean   want_daemonize = TRUE;
+gboolean   exit_on_control_eof = TRUE;
+gboolean   stdin_is_socket = FALSE;
+int        control_socket = -1;
+
+GIOChannel *control_channel;
+
 int        forground = 0;
 char      *listen_port = NETPERF_DEFAULT_SERVICE_NAME;  /* --port */
-uint16_t   listen_port_num = 0;                         /* --port */
+guint16    listen_port_num = 0;                         /* --port */
 char      *local_host_name       = NULL;
 int        local_address_family  = AF_UNSPEC;
-int        need_setup = 0;
+gboolean   need_setup = FALSE;
 
+int        orig_argc;
+gchar    **orig_argv;
+
 char	local_host_name_buf[BUFSIZ];
 char    local_addr_fam_buf[BUFSIZ];
 
-/* getopt_long return codes */
-enum {DUMMY_CODE=129
-      ,BRIEF_CODE
-};
+
 
-static struct option const long_options[] =
-{
-  {"output", required_argument, 0, 'o'},
-  {"input", required_argument, 0, 'i'},
-  {"config", required_argument, 0, 'c'},
-  {"debug", no_argument, 0, 'd'},
-  {"forground", no_argument, 0, 'f'},
-  {"quiet", no_argument, 0, 'q'},
-  {"local", required_argument, 0, 'L'},
-  {"silent", no_argument, 0, 'q'},
-  {"brief", no_argument, 0, BRIEF_CODE},
-  {"verbose", no_argument, 0, 'v'},
-  {"help", no_argument, 0, 'h'},
-  {"version", no_argument, 0, 'V'},
-  {NULL, 0, NULL, 0}
-};
+gboolean set_port_number(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
 
+  listen_port = g_strdup(option_value);
+  listen_port_num = atoi(listen_port);
+
+  return(TRUE);
+
+}
+gboolean set_local_address(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
+ 
+  break_args_explicit(option_value,local_host_name_buf,local_addr_fam_buf);
+  if (local_host_name_buf[0]) {
+    local_host_name = &local_host_name_buf[0];
+  }
+  if (local_addr_fam_buf[0]) {
+    local_address_family = parse_address_family(local_addr_fam_buf);
+    /* if only the address family was set, we may need to set the
+       local_host_name accordingly. since our defaults are IPv4 this
+       should only be necessary if we have IPv6 support raj
+       2005-02-07 */  
+#if defined (AF_INET6)
+    if (!local_host_name_buf[0]) {
+      strncpy(local_host_name_buf,"::0",sizeof(local_host_name_buf));
+      local_host_name = &local_host_name_buf[0];
+    }
+#endif
+  }
+
+  return(TRUE);
+}
+
+gboolean set_output_destination(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
+  oname = g_strdup(option_value);
+  ofile = fopen(oname, "w");
+  if (!ofile) {
+    g_fprintf(stderr,
+	    "%s: cannot open %s for writing\n",
+	    program_name,
+	    option_value);
+    exit(1);
+  }
+  return(TRUE);
+}
+
+gboolean do_closesocket(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
+  SOCKET toclose;
+
+  toclose = atoi(option_value);
+  g_fprintf(where,"was asked to close socket %d\n",toclose);
+#ifdef G_OS_WIN32
+  closesocket(toclose);
+#else
+  close(toclose);
+#endif
+  return(TRUE);
+}
+
+
+gboolean set_debug(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
+  if (option_value) {
+    /* set to value */
+    debug = atoi(option_value);
+  }
+  else {
+    /* simple increment */
+    debug++;
+  }
+  return(TRUE);
+}
+
+
+
+gboolean set_verbose(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
+  if (option_value) {
+    /* set to value */
+    want_verbose = atoi(option_value);
+  }
+  else {
+    /* simple increment */
+    want_verbose++;
+  }
+  return(TRUE);
+}
+  
+
+gboolean show_version(gchar *option_name, gchar *option_value, gpointer data, GError **error) {
+  g_printf("netserver: %s.%s.%s\n",
+	   NETPERF_VERSION,
+	   NETPERF_UPDATE,
+	   NETPERF_FIX);
+  exit(0);
+}
+
+gboolean
+spawn_new_netserver(int argc, char *argv[], SOCKET control, SOCKET toclose) {
+
+  int new_argc;
+  int i,j;
+  gboolean ret;
+  gboolean need_nodaemonize = TRUE;
+  gboolean need_nospawn = TRUE;
+  gchar **new_argv;
+  gchar control_string[10]; /* that should be more than enough
+			       characters I hope */
+  GPid new_pid;
+  GError *error=NULL;
+
+  /* while we will _probably_ be stripping things from the argument
+     vector, we want to make sure we have enough to add the control FD
+     specification and the --nospawn. */
+
+  new_argv = g_new(gchar *,argc+6);
+
+  for (i = 0, j = 0, new_argc = 0; i < argc; i++) {
+    /* this actually isn't correct for the future, but for now it will
+       suffice to test passing the control FD to the new process */
+    if (strcmp(argv[i],"--daemonize") == 0) {
+      if (need_nodaemonize) {
+	/* replace it with "--nodaemonize" in the new argument vector */
+	new_argv[j++] = g_strdup("--nodaemonize");
+	new_argc++;
+	need_nodaemonize = FALSE;
+      }
+      continue;
+    }
+    if (strcmp(argv[i],"--nodaemonize") == 0) {
+      if (need_nodaemonize) {
+	need_nodaemonize = FALSE;
+      }
+      else {
+	/* we already have one, so skip it */
+	continue;
+      }
+    }
+    if (strcmp(argv[i],"--nospawn") == 0) {
+      if (need_nospawn) {
+	need_nospawn = FALSE;
+      }
+      else {
+	/* skip it */
+	continue;
+      }
+    }
+    if (strcmp(argv[i],"--spawn") == 0) {
+      if (need_nospawn) {
+	/* replace it with --nospawn */
+	new_argv[j++] = g_strdup("--nospawn");
+	new_argc++;
+	need_nospawn = FALSE;
+      }
+      continue;
+    }
+    /* it is exceedingly unlikely that some of these options will be
+       in the original argument vector, but just in case */
+    if ((strcmp(argv[i],"--control") == 0) ||
+	(strcmp(argv[i],"--port") == 0) ||
+	(strcmp(argv[i],"-p") == 0) ||
+	(strcmp(argv[i],"-L") == 0) ||
+	(strcmp(argv[i],"--local") == 0)) {
+      /* we want to skip the option AND its argument */
+      i++;
+      continue;
+    }
+    /* otherwise, we just copy old to new */
+    new_argc++;
+    new_argv[j++] = g_strdup(argv[i]);
+
+  }
+  if (need_nospawn) {
+    new_argv[j++] = g_strdup("--nospawn"); /* don't recurse :) */
+    new_argc++;
+  }
+  if (need_nodaemonize) {
+    new_argv[j++] = g_strdup("--nodaemonize"); /* don't recurse */
+    new_argc++;
+  }
+  new_argv[j++] = g_strdup("--control");
+  g_snprintf(control_string,sizeof(control_string),"%d",control);
+  new_argv[j++] = g_strdup(control_string);
+  new_argc += 2;
+  new_argv[j++] = g_strdup("--closesocket");
+  g_snprintf(control_string,sizeof(control_string),"%d",toclose);
+  new_argv[j++] = g_strdup(control_string);
+  new_argc += 2;
+  new_argv[j] = NULL;
+
+  if (debug) {
+    g_fprintf(where,"spawning with new_argc of %d and:\n",new_argc);
+    for (i = 0; i < new_argc; i++) {
+      g_fprintf(where,"\targv[%d] %s\n",i,new_argv[i]);
+    }
+  }
+
+  ret = g_spawn_async_with_pipes(NULL,         /* working dir */
+				 new_argv,     /* argument vector */
+				 NULL,         /* env ptr */
+				 G_SPAWN_LEAVE_DESCRIPTORS_OPEN, /* flags */
+				 NULL,         /* setup func */
+				 NULL,         /* its arg */
+				 &new_pid,      /* new process' id */
+				 NULL,         /* dont watch stdin */
+				 NULL,         /* ditto stdout */
+				 NULL,         /* ditto stderr */
+				 &error);
+  if (error) {
+    g_warning("%s g_io_spawn_async_with_pipes %s %d %s\n",
+	      __func__,
+	      g_quark_to_string(error->domain),
+	      error->code,
+	      error->message);
+    g_clear_error(&error);
+  }
+  return(TRUE);
+}
+
+/* make a call to g_spawn_async_with_pipes to let us disconnect, at
+   least after a fashion, from the controlling terminal. we will
+   though remove the daemonze option from the argument vector used to
+   start the new process */
+
+gboolean
+daemonize(int argc, char *argv[]) {
+
+  int new_argc;
+  int i,j;
+  gboolean ret;
+  gboolean need_nodaemonize = TRUE;
+  char **new_argv;
+  GPid new_pid;
+  GError *error=NULL;
+
+  /* make sure we have room for the --nodeamonize option we will be adding */
+  new_argv = g_new(gchar *,argc+1);
+
+  /* it is slightly kludgy, but simply taking a --nodeamonize to the
+     end of the argument vector should suffice.  as things get more
+     sophisticated, we may want to strip certain options from the
+     vector. raj 2006-03-14 */
+
+  for (i = 0, j = 0, new_argc = 0; i < argc; i++) {
+    if (strcmp(argv[i], "--daemonize") == 0) {
+      if (need_nodaemonize) {
+	/* replace with --nodaemonize" */
+	new_argv[j++] = g_strdup("--nodaemonize");
+	new_argc++;
+	need_nodaemonize = FALSE;
+      }
+      continue;
+    }
+    /* I seriously doubt we'd ever hit this but still */
+    if (strcmp(argv[i],"--nodaemonize") == 0) {
+      if (need_nodaemonize) {
+	need_nodaemonize = FALSE;
+      }
+      else {
+	/* skip it */
+	continue;
+      }
+    }
+
+    /* otherwise, we just copy old to new */
+    new_argc++;
+    new_argv[j++] = g_strdup(argv[i]);
+  }
+  if (need_nodaemonize) {
+    new_argv[j++] = g_strdup("--nodaemonize");
+    new_argc++;
+  }
+  new_argv[j] = NULL;
+
+  if (debug) {
+    g_fprintf(where,"daemonizing with new_argc of %d and:\n",new_argc);
+    for (i = 0; i < new_argc; i++) {
+      g_fprintf(where,"\targv[%d] %s\n",i,new_argv[i]);
+    }
+  }
+
+  ret = g_spawn_async_with_pipes(NULL,         /* working dir */
+				 new_argv,     /* argument vector */
+				 NULL,         /* env ptr */
+				 G_SPAWN_LEAVE_DESCRIPTORS_OPEN, /* flags */
+				 NULL,         /* setup func */
+				 NULL,         /* its arg */
+				 &new_pid,      /* new process' id */
+				 NULL,         /* dont watch stdin */
+				 NULL,         /* ditto stdout */
+				 NULL,         /* ditto stderr */
+				 &error);
+  if (error) {
+    g_warning("%s g_io_spawn_async_with_pipes %s %d %s\n",
+	      __func__,
+	      g_quark_to_string(error->domain),
+	      error->code,
+	      error->message);
+    g_clear_error(&error);
+  }
+  exit(0);
+}
+
 static void
 usage (int status)
 {
@@ -192,100 +474,8 @@
   exit (status);
 }
 
-/* Set all the option flags according to the switches specified.
-   Return the index of the first non-option argument.  */
 
-static int
-decode_command_line (int argc, char **argv)
-{
-  int c;
 
-  while ((c = getopt_long (argc, argv,
-			   "d"  /* debug */
-			   "f"  /* forground */
-			   "L:" /* local control sock address info */
-                           "o:" /* output */
-                           "p:" /* port */
-                           "q"  /* quiet or silent */
-                           "v"  /* verbose */
-                           "h"  /* help */
-                           "V", /* version */
-                           long_options, (int *) 0)) != EOF)
-    {
-      switch (c)
-        {
-	case 'd':       /* --debug */
-	  debug++;
-	  break;
-        case 'f':       /* --forground */
-          forground++;  /* 1 means no deamon, 2 means no fork after accept */
-	  need_setup = 1;
-          break;
-	case 'L':
-	  break_args_explicit(optarg,local_host_name_buf,local_addr_fam_buf);
-	  if (local_host_name_buf[0]) {
-            local_host_name = &local_host_name_buf[0];
-	  }
-	  if (local_addr_fam_buf[0]) {
-	    local_address_family = parse_address_family(local_addr_fam_buf);
-	    /* if only the address family was set, we may need to set the
-	       local_host_name accordingly. since our defaults are IPv4
-	       this should only be necessary if we have IPv6 support raj
-	       2005-02-07 */  
-#if defined (AF_INET6)
-	    if (!local_host_name_buf[0]) {
-	      strncpy(local_host_name_buf,"::0",sizeof(local_host_name_buf));
-              local_host_name = &local_host_name_buf[0];
-	    }
-#endif
-	  }
-	  need_setup = 1;
-	  break;
-        case 'o':               /* --output */
-          oname = strdup(optarg);
-          ofile = fopen(oname, "w");
-          if (!ofile) {
-            fprintf(stderr,
-                    "%s: cannot open %s for writing\n",
-                    program_name,
-                    optarg);
-              exit(1);
-            }
-          break;
-        case 'p':               
-          /* we want to open a listen socket at a */
-          /* specified port number */
-          listen_port = strdup(optarg);
-          listen_port_num = atoi(listen_port);
-	  need_setup = 1;
-          break;
-        case 'q':               /* --quiet, --silent */
-          want_quiet = 1;
-          break;
-        case BRIEF_CODE:        /* --brief */
-          want_brief = 1;
-          break;
-        case 'v':               /* --verbose */
-          want_verbose = 1;
-          break;
-        case 'V':
-          printf ("netserver %s.%s.%s\n",
-                  NETPERF_VERSION,
-                  NETPERF_UPDATE,
-                  NETPERF_FIX);
-          exit (0);
-        case 'h':
-          usage (0);
-        default:
-          usage (EXIT_FAILURE);
-        }
-    }
-
-  return optind;
-}
-
-
-
 int
 add_netperf_to_hash(server_t *new_netperf) {
 
@@ -385,19 +575,19 @@
     rc = recv_control_message(sock,&message);
     if (rc > 0) { /* received a message */
       if (debug) {
-        fprintf(where, "Received a control message to doc %p\n", message);
+        g_fprintf(where, "Received a control message to doc %p\n", message);
         fflush(where);
       }
       msg = xmlDocGetRootElement(message);
       if (msg == NULL) {
-        fprintf(stderr,"empty document\n");
+        g_fprintf(stderr,"empty document\n");
         xmlFreeDoc(message);
         rc = NPE_EMPTY_MSG;
       } else {
         cur = msg->xmlChildrenNode;
         if (xmlStrcmp(cur->name,(const xmlChar *)"version")!=0) {
           if (debug) {
-            fprintf(where,
+            g_fprintf(where,
                     "%s: Received an unexpected message\n", __func__);
             fflush(where);
           }
@@ -408,7 +598,7 @@
           from_nid = xmlStrdup(xmlGetProp(msg,(const xmlChar *)"fromnid"));
 
           if ((netperf = (server_t *)malloc(sizeof(server_t))) == NULL) {
-            fprintf(where,"%s: malloc failed\n", __func__);
+            g_fprintf(where,"%s: malloc failed\n", __func__);
             fflush(where);
             exit(1);
           }
@@ -431,7 +621,7 @@
     } 
     else {
       if (debug) {
-        fprintf(where,"%s: close connection remote close\n", __func__);
+        g_fprintf(where,"%s: close connection remote close\n", __func__);
         fflush(where);
       }
       close(sock);
@@ -447,65 +637,7 @@
   return(rc);
 }
 
-/* daemonize will fork a daemon into the background, freeing-up the
-   shell prompt for other uses. I suspect that for non-Unix OSes,
-   something other than fork() may be required? raj 2/98 */
-void
-daemonize()
-{
-  char filename[PATH_MAX];
 
-  /* fork off - only the client will return, the parent will exit */
-  
-  switch (fork()) {
-  case -1:
-    /* something went wrong */
-    perror("netserver fork error");
-    exit(-1);
-  case 0:
-    /* we are the child process. set ourselves up as the session
-       leader so we detatch from the parent, and then return to the
-       caller so he can do whatever it is he wants to do */
-
-    fclose(stdin);
-
-    snprintf(filename,
-	     PATH_MAX,
-	     "%s%s%d%s",
-	     NETPERF_DEBUG_LOG_DIR,
-	     NETPERF_DEBUG_LOG_PREFIX,
-	     getpid(),
-	     NETPERF_DEBUG_LOG_SUFFIX);
-    where = freopen(filename,"w",where);
-    if (NULL == where) {
-      fprintf(stderr,
-	      "ERROR netserver could not freopen where to %s errno %d\n",
-	      filename,
-	      errno);
-      fflush(stderr);
-      exit(-1);
-    }
-
-    /* at this point should I close stderr?!? */
-    setsid();
-
-    /* not all OSes have SIGCLD as SIGCHLD */
-#ifndef SIGCLD
-#define SIGCLD SIGCHLD
-#endif /* SIGCLD */
-    
-    signal(SIGCLD, SIG_IGN);
-
-    break;
-  default:
-    /* we are the parent process - the one invoked from the
-       shell. since the first child will detach itself, we can just go
-       ahead and slowly fade away */
-    exit(0);
-  }
-}
-
-
 static void
 report_stuck_test_status(server_t *netperf)
 {
@@ -566,7 +698,7 @@
       if (orig != new) {
         /* report change in test state */
         if (debug) {
-          fprintf(where,"%s:tid = %s  state %d  new_state %d\n",
+          g_fprintf(where,"%s:tid = %s  state %d  new_state %d\n",
                   __func__, test->id, orig, new);
           fflush(where);
         }
@@ -613,7 +745,7 @@
           rc = send_control_message(netperf->sock, msg, netperf->id, my_nid);
           if (rc != NPE_SUCCESS) {
             if (debug) {
-              fprintf(where,
+              g_fprintf(where,
                       "%s: send_control_message failed\n", __func__);
               fflush(where);
             }
@@ -693,7 +825,7 @@
       rc = send_control_message(netperf->sock, msg, netperf->id, my_nid);
       if (rc != NPE_SUCCESS) {
         if (debug) {
-          fprintf(where,
+          g_fprintf(where,
                   "%s: send_control_message failed\n", __func__);
           fflush(where);
         }
@@ -702,8 +834,8 @@
     delete_netperf(netperf->id);
   } else {
     /* we should never really get here   sgb  2005-12-06 */
-    fprintf(where, "%s entered through some unknown path!!!!\n", __func__);
-    fprintf(where, "netperf->state_req = %d \t netperf->err_rc = %d\n",
+    g_fprintf(where, "%s entered through some unknown path!!!!\n", __func__);
+    g_fprintf(where, "netperf->state_req = %d \t netperf->err_rc = %d\n",
             netperf->state_req, netperf->err_rc);
     fflush(where);
     exit(-2);
@@ -724,7 +856,7 @@
 
   rc = instantiate_netperf(sock);
   if (rc != NPE_SUCCESS) {
-    fprintf(where,
+    g_fprintf(where,
             "%s %s: instantiate_netperf  error %d\n",
             program_name,
             __func__,
@@ -754,7 +886,7 @@
       if (rc > 0) {
         rc = process_message(netperf, message);
         if (rc) {
-          fprintf(where,"process_message returned %d  %s\n",
+          g_fprintf(where,"process_message returned %d  %s\n",
                   rc, netperf_error_name(rc));
           fflush(where);
         }
@@ -764,7 +896,7 @@
         if (rc == 0) {
           netperf->err_rc = NPE_REMOTE_CLOSE;
         } else {
-          fprintf(where,"recv_control_message returned %d  %s\n",
+          g_fprintf(where,"recv_control_message returned %d  %s\n",
                   rc, netperf_error_name(rc));
           fflush(where);
           netperf->err_rc = rc;
@@ -772,7 +904,7 @@
       }
     } else {
       if (debug) {
-        fprintf(where,"ho hum, nothing to do\n");
+        g_fprintf(where,"ho hum, nothing to do\n");
         fflush(where);
         report_servers_test_status(netperf);
       }
@@ -800,16 +932,68 @@
 }
 
 
+/* called when it is time to accept a new control connection off the
+   listen endpoint */
+gboolean  accept_connection(GIOChannel *source,
+			    GIOCondition condition,
+			    gpointer data) {
+  SOCKET control_socket;
+  SOCKET listen_socket;
+  gboolean ret;
 
-static void
+  g_fprintf(where,"accepting a new connection\n");
+
+#ifdef G_OS_WIN32
+  listen_socket = g_io_channel_win32_get_fd(source);
+#else
+  listen_socket = g_io_channel_unix_get_fd(source);
+#endif
+
+  control_socket = accept(listen_socket,NULL,0);
+  if (control_socket == SOCKET_ERROR) {
+    g_fprintf(where,
+	      "%s: accept failed errno %d %s\n",
+	      __func__,
+	      errno,
+	      strerror(errno));
+    fflush(where);
+    exit(-1);
+  }
+  if (debug) {
+    g_fprintf(where,
+	      "%s: accepted connection on sock %d\n",
+	      __func__,
+	      control_socket);
+    fflush(where);
+  }
+    
+  if (spawn_on_accept) {
+    ret = spawn_new_netserver(orig_argc,orig_argv,
+			      control_socket,listen_socket);
+    CLOSE_SOCKET(control_socket);  /* don't want to leak descriptors */
+  }
+  else {
+    /* for now, we will simply start processing requests the
+       "original" way. later we will establish a recv callback for a
+       proper glib event loop */
+    g_fprintf(where,"accepted a connection but told not to spawn\n");
+    handle_netperf_requests(control_socket);
+    CLOSE_SOCKET(control_socket);
+  }
+
+  return(TRUE);
+}
+
+
+static SOCKET
 setup_listen_endpoint(char service[]) {
 
   struct sockaddr   name;
   struct sockaddr  *peeraddr     = &name;
   int               namelen      = sizeof(name);
   netperf_socklen_t peerlen      = namelen;
-  int               sock;
-  int               listenfd     = 0;
+  SOCKET            sock;
+  SOCKET            listenfd     = 0;
   int               loop         = 1;
   char              filename[PATH_MAX];
 
@@ -830,17 +1014,21 @@
                                 &peerlen);
 
     if (listenfd == -1) {
-      fprintf(where,"%s: failed to open listen socket\n", __func__);
+      g_fprintf(where,"%s: failed to open listen socket\n", __func__);
       fflush(where);
       exit(1);
     }
-
+  return(listenfd);
+  }
+  return(-1);
+}
+#ifdef notdef
     if (peerlen > namelen) {
       peeraddr = (struct sockaddr *)malloc (peerlen);
     }
 
     if (!forground) {
-      daemonize();
+      daemonize(orig_argc, orig_argv);
     }
 
     /* loopdeloop */
@@ -848,7 +1036,7 @@
     while (loop) {
       printf("about to accept on socket %d\n",listenfd);
       if ((sock = accept(listenfd,peeraddr,&peerlen)) == -1) {
-	fprintf(where,
+	g_fprintf(where,
 		"%s: accept failed errno %d %s\n",
                 __func__,
 		errno,
@@ -857,7 +1045,7 @@
 	exit(1);
       }
       if (debug) {
-	fprintf(where,
+	g_fprintf(where,
 		"%s: accepted connection on sock %d\n",
                 __func__,
 		sock);
@@ -903,7 +1091,7 @@
 	  
 	  where = freopen(filename,"w",where);
 	  if (NULL == where) {
-	    fprintf(stderr,
+	    g_fprintf(stderr,
 		    "ERROR netserver could not freopen where to %s errno %d\n",
 		    filename,
 		    errno);
@@ -925,8 +1113,8 @@
     }
   }
 }
+#endif
 
-
 /* Netserver initialization */
 static void
 netserver_init()
@@ -943,14 +1131,14 @@
     netperf_hash[i].hash_lock = g_mutex_new();
     if (NULL == netperf_hash[i].hash_lock) {
       /* not sure we will even get here */
-      fprintf(where, "%s: g_mutex_new error \n",__func__);
+      g_fprintf(where, "%s: g_mutex_new error \n",__func__);
       fflush(where);
       exit(-2);
     }
     netperf_hash[i].condition = g_cond_new();
     if (NULL == netperf_hash[i].condition) {
       /* not sure we will even get here */
-      fprintf(where, "%s: g_cond_new error \n",__func__);
+      g_fprintf(where, "%s: g_cond_new error \n",__func__);
       fflush(where);
       exit(-2);
     }
@@ -959,14 +1147,14 @@
       (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
 
     if (NULL == netperf_hash[i].hash_lock) {
-      fprintf(where, "%s: unable to malloc a mutex \n",__func__);
+      g_fprintf(where, "%s: unable to malloc a mutex \n",__func__);
       fflush(where);
       exit(-2);
     }
 
     rc = pthread_mutex_init(netperf_hash[i].hash_lock, NULL);
     if (rc) {
-      fprintf(where, "%s: server pthread_mutex_init error %d\n", __func__, rc);
+      g_fprintf(where, "%s: server pthread_mutex_init error %d\n", __func__, rc);
       fflush(where);
       exit(rc);
     }
@@ -975,14 +1163,14 @@
       (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
 
     if (NULL == netperf_hash[i].condition) {
-      fprintf(where, "%s: unable to malloc a pthread_cond_t \n",__func__);
+      g_fprintf(where, "%s: unable to malloc a pthread_cond_t \n",__func__);
       fflush(where);
       exit(-2);
     }
       
     rc = pthread_cond_init(netperf_hash[i].condition, NULL);
     if (rc) {
-      fprintf(where, "%s: server pthread_cond_init error %d\n", __func__, rc);
+      g_fprintf(where, "%s: server pthread_cond_init error %d\n", __func__, rc);
       fflush(where);
       exit(rc);
     }
@@ -995,14 +1183,14 @@
     test_hash[i].hash_lock = g_mutex_new();
     if (NULL == test_hash[i].hash_lock) {
       /* not sure we will even get here */
-      fprintf(where, "%s: g_cond_new error \n",__func__);
+      g_fprintf(where, "%s: g_cond_new error \n",__func__);
       fflush(where);
       exit(-2);
     }
     test_hash[i].condition = g_cond_new();
     if (NULL == test_hash[i].condition) {
       /* not sure we will even get here */
-      fprintf(where, "%s: g_cond_new error \n",__func__);
+      g_fprintf(where, "%s: g_cond_new error \n",__func__);
       fflush(where);
       exit(-2);
     }
@@ -1011,14 +1199,14 @@
       (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
 
     if (NULL == test_hash[i].hash_lock) {
-      fprintf(where, "%s: unable to malloc a mutex \n",__func__);
+      g_fprintf(where, "%s: unable to malloc a mutex \n",__func__);
       fflush(where);
       exit(-2);
     }
 
     rc = pthread_mutex_init(test_hash[i].hash_lock, NULL);
     if (rc) {
-      fprintf(where, "%s: test pthread_mutex_init error %d\n", __func__, rc);
+      g_fprintf(where, "%s: test pthread_mutex_init error %d\n", __func__, rc);
       fflush(where);
       exit(rc);
     }
@@ -1026,14 +1214,14 @@
       (pthread_cond_t *)malloc(sizeof(pthread_cond_t));
 
     if (NULL == test_hash[i].condition) {
-      fprintf(where, "%s: unable to malloc a pthread_cond_t \n",__func__);
+      g_fprintf(where, "%s: unable to malloc a pthread_cond_t \n",__func__);
       fflush(where);
       exit(-2);
     }
 
     rc = pthread_cond_init(test_hash[i].condition, NULL);
     if (rc) {
-      fprintf(where, "%s: test pthread_cond_init error %d\n", __func__, rc);
+      g_fprintf(where, "%s: test pthread_cond_init error %d\n", __func__, rc);
       fflush(where);
       exit(rc);
     }
@@ -1045,38 +1233,113 @@
 }
 
 
+static GOptionEntry netserver_entries[] =
+  {
+    {"daemonize", 0, 0, G_OPTION_ARG_NONE, &want_daemonize, "When launched from a shell, disconnect from that shell (default)", NULL},
+    {"nodaemonize", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &want_daemonize, "When launched from a shell, do not disconnect from that shell", NULL},
+    {"spawn", 0, 0, G_OPTION_ARG_NONE, &spawn_on_accept, "Spawn a new process for each control connection (default)", NULL},
+    {"nospawn", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &spawn_on_accept, "Do not spawn a new process for each control connection", NULL},
+    {"control", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &control_socket, "The FD that should be used for the control channel (internal)", NULL},
+    {"closesocket", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, do_closesocket,"Close the specified socket", NULL},
+    {"local", 'L', 0, G_OPTION_ARG_CALLBACK, set_local_address, "Specify the local addressing for the control endpoint", NULL},
+    {"output", 'o', 0, G_OPTION_ARG_CALLBACK, set_output_destination, "Specify where misc. output should go", NULL},
+    {"port", 'p', 0, G_OPTION_ARG_CALLBACK, set_port_number, "Specify the port number for the control connection", NULL},
+    {"debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, set_debug, "Set the level of debugging",NULL},
+    {"version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version, "Display the netserver version and exit", NULL},
+    {"verbose", 'v', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, set_verbose, "Set verbosity level for output", NULL},
+    {"brief", 'b', 0, G_OPTION_ARG_NONE, &want_brief, "Request brief output", NULL},
+    {"quiet", 'q', 0, G_OPTION_ARG_NONE, &want_quiet, "Display no test banners", NULL},
+    { NULL }
+  };
 
+
 int
-main (int argc, char **argv)
+main(int argc, char **argv)
 {
 
-  int sock;
+  int i;
   struct sockaddr name;
   netperf_socklen_t namelen = sizeof(name);
+  SOCKET sock, listen_sock;
 
+  guint  watch_id;
+  GOptionContext *option_context;
+  gboolean ret;
+  GError *error = NULL;
+  GIOStatus status;
+  GMainLoop *loop;
+
+#ifdef G_OS_WIN32
+  WSADATA	wsa_data ;
+
+#endif
+  /* make sure that where points somewhere to begin with */
+  where = stderr;
+
+#ifdef G_OS_WIN32
+  /* Initialize the winsock lib ( version 2.2 ) */
+  if ( WSAStartup(MAKEWORD(2,2), &wsa_data) == SOCKET_ERROR ){
+    g_fprintf(where,"WSAStartup() failed : %d\n", GetLastError()) ;
+    return 1 ;
+  }
+#endif
+  
   program_name = argv[0];
 
 #ifdef WITH_GLIB
   g_thread_init(NULL);
 #endif
 
-  /* if netserver is invoked with any of the -L, -p or -f options it
-     will necessary to setup the listen endpoint.  similarly, if
-     standard in is not a socket, it will be necessary to setup the
-     listen endpoint.  otherwise, we assume we sprang-forth from inetd
-     or the like and should start processing requests. */
+  /* save-off the initial command-line stuff in case we need it for
+     daemonizing or spawning after an accept */
+  orig_argc = argc;
+  orig_argv = g_new(gchar *,argc);
+  for (i = 0; i < argc; i++){
+    orig_argv[i] = g_strdup(argv[i]);
+  }
 
-  if (getsockname(0, &name, &namelen) == -1) {
-      /* we may not be a child of inetd */
-      if (CHECK_FOR_NOT_SOCKET) {
-	need_setup = 1;
-      }
+  option_context = g_option_context_new(" - netperf4 netserver options");
+  g_option_context_add_main_entries(option_context,netserver_entries, NULL);
+  ret = g_option_context_parse(option_context, &argc, &argv, &error);
+  if (error) {
+    /* it sure would be nice to know how to trigger the help output */
+    g_error("%s g_option_context_parse %s %d %s\n",
+	      __func__,
+	      g_quark_to_string(error->domain),
+	      error->code,
+	      error->message);
+    g_clear_error(&error);
   }
 
-  decode_command_line(argc, argv);
+  /* if we daemonize, we will not be returning, and we will be
+     starting a whole new instance of this binary, because that is what
+     g_spawn_asyync_with_pipes() does. */
+  if (want_daemonize) {
+    daemonize(orig_argc,orig_argv);
+  }
 
+  /* if neither stdin, nor control_socket are sockets, we need to
+     setup a listen endpoint and go from there, otherwise, we assume
+     we are a child of inetd or launched from a parent netserver raj
+     2006-03-16 */
+
+  if (getsockname(0, &name, &namelen) == 0) {
+    /* we are a child of inetd or the like */
+    need_setup = FALSE;
+    sock = 0;
+  }
+  else if (getsockname(control_socket, &name, &namelen) == 0) {
+    /* we were spawned by a parent netserver */
+    need_setup = FALSE;
+    sock = control_socket;
+  }
+  else {
+    need_setup = TRUE;
+  }
+
   if (ofile) {
-    /* send our stuff to wherever the user told us to */
+    /* send our stuff to wherever the user told us to. likely we need
+       to revisit this in the face of spawning processes... */
     where = ofile;
   }
   else {
@@ -1126,24 +1389,51 @@
      whether we are a child of inetd or not. raj 2005-10-11 */
   netserver_init();
 
-  /* if netserver is invoked with any of the -L, -p or -f options it
-     will necessary to setup the listen endpoint.  similarly, if
-     standard in is not a socket, it will be necessary to setup the
-     listen endpoint.  otherwise, we assume we sprang-forth from inetd
-     or the like and should start processing requests. */
+  loop = g_main_loop_new(NULL, FALSE);
 
-  if (getsockname(0, &name, &namelen) == -1) {
-      /* we may not be a child of inetd */
-      if (CHECK_FOR_NOT_SOCKET) {
-	need_setup = 1;
-      }
-  }
+  if (need_setup) {
+    listen_sock = setup_listen_endpoint(listen_port);
+#ifdef G_OS_WIN32
+    control_channel = g_io_channel_win32_new_socket(listen_sock);
+#else
+    control_channel = g_io_channel_unix_new(listen_sock);
+#endif
+    status = g_io_channel_set_flags(control_channel,G_IO_FLAG_NONBLOCK,&error);
+    if (error) {
+      g_warning("g_io_channel_set_flags %s %d %s\n",
+		g_quark_to_string(error->domain),
+		error->code,
+		error->message);
+      g_clear_error(&error);
+    }
+    g_print("status after set flags %d control_channel %p\n",status,control_channel);
+    
+    status = g_io_channel_set_encoding(control_channel,NULL,&error);
+    if (error) {
+      g_warning("g_io_channel_set_encoding %s %d %s\n",
+		g_quark_to_string(error->domain),
+		error->code,
+		error->message);
+      g_clear_error(&error);
+    }
+    
+    g_print("status after set_encoding %d\n");
+    
+    g_io_channel_set_buffered(control_channel,FALSE);
+    
+    /* loop is passed just to have something passed */
+    watch_id = g_io_add_watch(control_channel, 
+			      G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
+			      accept_connection,
+			      loop);
+    g_print("added watch id %d\n",watch_id);
 
-  if (need_setup) {
-    setup_listen_endpoint(listen_port);
+    g_print("Starting loop to accept stuff...\n");
+    g_main_loop_run(loop);
+    g_print("Came out of the main loop\n");
+
   }
   else {
-    sock = 0;
     handle_netperf_requests(sock);
   }
 }



More information about the netperf-dev mailing list