void
setup_listens(char name[], char port[], int af) {

  int do_inet;
  int no_name = 0;
#ifdef AF_INET6
  int do_inet6;
#endif

  if (debug) {
    fprintf(where,
	    "%s: enter\n",
	    __FUNCTION__);
    fflush(where);
  }


  if (strcmp(name,"") == 0) {
    no_name = 1;
    switch (af) {
    case AF_UNSPEC:
      do_inet = 1;
#ifdef AF_INET6
      do_inet6 = 1;
#endif
      break;
    case AF_INET:
      do_inet = 1;
#ifdef AF_INET6
      do_inet6 = 0;
#endif
      break;
#ifdef AF_INET6
    case AF_INET6:
      do_inet = 0;
      do_inet6 = 1;
      break;
#endif
    default:
      do_inet = 1;
    }
    /* if we have IPv6, try that one first because it may be a superset */
#ifdef AF_INET6
    if (do_inet6)
      create_listens("::0",port,AF_INET6);
#endif
    if (do_inet)
      create_listens("0.0.0.0",port,AF_INET);
  }
  else {
    create_listens(name,port,af);
  }

  if (listen_list) {
    fprintf(stdout,
	    "Starting netserver with host '%s' port '%s' and family %s\n",
	    (no_name) ? "IN(6)ADDR_ANY" : name,
	    port,
	    inet_ftos(af));
    fflush(stdout);
  }
  else {
    fprintf(stderr,
	    "Unable to start netserver with  '%s' port '%s' and family %s\n",
	    (no_name) ? "IN(6)ADDR_ANY" : name,
	    port,
	    inet_ftos(af));
    fflush(stderr);
    exit(1);
  }
}
Пример #2
0
void 
set_up_server(char hostname[], char port[], int af)
{ 

  struct addrinfo     hints;
  struct addrinfo     *local_res;
  struct addrinfo     *local_res_temp;

  struct sockaddr_storage     peeraddr;
  netperf_socklen_t                 peeraddr_len = sizeof(peeraddr);
  
  SOCKET server_control;
  int on=1;
  int count;
  int error;
  int not_listening;

#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
  FILE *rd_null_fp;    /* Used to redirect from "/dev/null". */
  FILE *wr_null_fp;    /* Used to redirect to   "/dev/null". */
#endif /* !WIN32 !MPE !__VMS */

  if (debug) {
    fprintf(stderr,
            "set_up_server called with host '%s' port '%s' remfam %d\n",
            hostname,
	    port,
            af);
    fflush(stderr);
  }

  memset(&hints,0,sizeof(hints));
  hints.ai_family = af;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;
  hints.ai_flags = AI_PASSIVE;

  count = 0;
  do {
    error = getaddrinfo((char *)hostname,
                        (char *)port,
                        &hints,
                        &local_res);
    count += 1;
    if (error == EAI_AGAIN) {
      if (debug) {
        fprintf(stderr,"Sleeping on getaddrinfo EAI_AGAIN\n");
        fflush(stderr);
      }
      sleep(1);
    }
  } while ((error == EAI_AGAIN) && (count <= 5));

  if (error) {
    fprintf(stderr,
	    "set_up_server: could not resolve remote '%s' port '%s' af %d",
	    hostname,
	    port,
	    af);
    fprintf(stderr,"\n\tgetaddrinfo returned %d %s\n",
	    error,
	    gai_strerror(error));
    exit(-1);
  }

  if (debug) {
    dump_addrinfo(stderr, local_res, hostname, port, af);
  }

  not_listening = 1;
  local_res_temp = local_res;

  while((local_res_temp != NULL) && (not_listening)) {

    fprintf(stderr,
	    "Starting netserver at port %s\n",
	    port);

    server_control = socket(local_res_temp->ai_family,SOCK_STREAM,0);

    if (server_control == INVALID_SOCKET) {
      perror("set_up_server could not allocate a socket");
      exit(-1);
    }

    /* happiness and joy, keep going */
    if (setsockopt(server_control, 
		   SOL_SOCKET, 
		   SO_REUSEADDR, 
		   (char *)&on , 
		   sizeof(on)) == SOCKET_ERROR) {
      if (debug) {
	perror("warning: set_up_server could not set SO_REUSEADDR");
      }
    }
    /* still happy and joyful */

    if ((bind (server_control, 
	       local_res_temp->ai_addr, 
	       local_res_temp->ai_addrlen) != SOCKET_ERROR) &&
	(listen (server_control,5) != SOCKET_ERROR))  {
      not_listening = 0;
      break;
    }
    else {
      /* we consider a bind() or listen() failure a transient and try
	 the next address */
      if (debug) {
	perror("warning: set_up_server failed a bind or listen call\n");
      }
      local_res_temp = local_res_temp->ai_next;
      continue;
    }
  }

  if (not_listening) {
    fprintf(stderr,
	    "set_up_server could not establish a listen endpoint for %s port %s with family %s\n",
	    host_name,
	    port,
	    inet_ftos(af));
    fflush(stderr);
    exit(-1);
  }
  else {
    printf("Starting netserver at hostname %s port %s and family %s\n",
	   hostname,
	   port,
	   inet_ftos(af));
  }

  /*
    setpgrp();
    */

#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
  /* Flush the standard I/O file descriptors before forking. */
  fflush (stdin);
  fflush (stdout);
  fflush (stderr);
#if defined(HAVE_FORK)
  switch (fork())
#else
  switch (vfork())
#endif
    {
    case -1:  	
      perror("netperf server error");
      exit(1);
      
    case 0:	
      /* Redirect stdin from "/dev/null". */
      rd_null_fp = fopen ("/dev/null", "r");
      if (rd_null_fp == NULL)
      {
	perror ("netserver: opening for reading: /dev/null");
	exit   (1);
      }
      if (close (STDIN_FILENO) == -1)
      {
	perror ("netserver: closing stdin file descriptor");
	exit   (1);
      }
      if (dup (fileno (rd_null_fp)) == -1)
      {
	perror ("netserver: duplicate /dev/null read file descr. to stdin");
	exit   (1);
      }

      /* Redirect stdout to the debug write file descriptor. */
      if (close (STDOUT_FILENO) == -1)
      {
	perror ("netserver: closing stdout file descriptor");
	exit   (1);
      }
      if (dup (fileno (where))  == -1)
      {
	perror ("netserver: duplicate the debug write file descr. to stdout");
	exit   (1);
      }

      /* Redirect stderr to "/dev/null". */
      wr_null_fp = fopen ("/dev/null", "w");
      if (wr_null_fp == NULL)
      {
	perror ("netserver: opening for writing: /dev/null");
	exit   (1);
      }
      if (close (STDERR_FILENO) == -1)
      {
	perror ("netserver: closing stderr file descriptor");
	exit   (1);
      }
      if (dup (fileno (wr_null_fp))  == -1)
      {
	perror ("netserver: dupicate /dev/null write file descr. to stderr");
	exit   (1);
      }
 
#ifndef NO_SETSID
      setsid();
#else
      setpgrp();
#endif /* NO_SETSID */

 /* some OS's have SIGCLD defined as SIGCHLD */
#ifndef SIGCLD
#define SIGCLD SIGCHLD
#endif /* SIGCLD */

      signal(SIGCLD, SIG_IGN);
      
#endif /* !WIN32 !MPE !__VMS */

      for (;;)
	{
	  if ((server_sock=accept(server_control,
				  (struct sockaddr *)&peeraddr,
				  &peeraddr_len)) == INVALID_SOCKET)
	    {
	      printf("server_control: accept failed errno %d\n",errno);
	      exit(1);
	    }
#if defined(MPE) || defined(__VMS)
	  /*
	   * Since we cannot fork this process , we cant fire any threads
	   * as they all share the same global data . So we better allow
	   * one request at at time 
	   */
	  process_requests() ;
#elif WIN32
		{
			BOOL b;
			char cmdline[80];
			PROCESS_INFORMATION pi;
			STARTUPINFO si;
			int i;

			memset(&si, 0 , sizeof(STARTUPINFO));
			si.cb = sizeof(STARTUPINFO);

			/* Pass the server_sock as stdin for the new process. */
			/* Hopefully this will continue to be created with the OBJ_INHERIT attribute. */
			si.hStdInput = (HANDLE)server_sock;
			si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
			si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
			si.dwFlags = STARTF_USESTDHANDLES;

			/* Build cmdline for child process */
			strcpy(cmdline, program);
			if (verbosity > 1) {
				snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -v %d", verbosity);
			}
			for (i=0; i < debug; i++) {
				snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -d");
			}
			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -I %x", (int)(UINT_PTR)server_sock);
			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)server_control);
			snprintf(&cmdline[strlen(cmdline)], sizeof(cmdline) - strlen(cmdline), " -i %x", (int)(UINT_PTR)where);

			b = CreateProcess(NULL,	 /* Application Name */
					cmdline,
					NULL,    /* Process security attributes */
					NULL,    /* Thread security attributes */
					TRUE,    /* Inherit handles */
					0,	   /* Creation flags  PROCESS_QUERY_INFORMATION,  */
					NULL,    /* Enviornment */
					NULL,    /* Current directory */
					&si,	   /* StartupInfo */
					&pi);
			if (!b)
			{
				perror("CreateProcessfailure: ");
				exit(1);
			}

			/* We don't need the thread or process handles any more; let them */
			/* go away on their own timeframe. */

			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);

			/* And close the server_sock since the child will own it. */

			close(server_sock);
		}
#else
      signal(SIGCLD, SIG_IGN);
#if defined(HAVE_FORK)
	  switch (fork())
#else
	  switch (vfork())
#endif
	    {
	    case -1:
	      /* something went wrong */
	      exit(1);
	    case 0:
	      /* we are the child process */
	      close(server_control);
	      process_requests();
	      exit(0);
	      break;
	    default:
	      /* we are the parent process */
	      close(server_sock);
	      /* we should try to "reap" some of our children. on some */
	      /* systems they are being left as defunct processes. we */
	      /* will call waitpid, looking for any child process, */
	      /* with the WNOHANG feature. when waitpid return a zero, */
	      /* we have reaped all the children there are to reap at */
	      /* the moment, so it is time to move on. raj 12/94 */
#ifndef DONT_WAIT
#ifdef NO_SETSID
	      /* Only call "waitpid()" if "setsid()" is not used. */
	      while(waitpid(-1, NULL, WNOHANG) > 0) { }
#endif /* NO_SETSID */
#endif /* DONT_WAIT */
	      break;
	    }
#endif /* !WIN32 !MPE !__VMS */  
	} /*for*/
#if !defined(WIN32) && !defined(MPE) && !defined(__VMS)
      break; /*case 0*/
      
    default: 
      exit (0);
      
    }
#endif /* !WIN32 !MPE !__VMS */  
}
void
create_listens(char hostname[], char port[], int af) {

  struct addrinfo hints;
  struct addrinfo *local_res;
  struct addrinfo *local_res_temp;
  int count, error;
  int on = 1;
  SOCKET temp_socket;
  struct listen_elt *temp_elt;

  if (debug) {
    fprintf(stderr,
	    "%s: called with host '%s' port '%s' family %s(%d)\n",
	    __FUNCTION__,
            hostname,
	    port,
	    inet_ftos(af),
            af);
    fflush(stderr);
  }
 memset(&hints,0,sizeof(hints));
  hints.ai_family = af;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;
  hints.ai_flags = AI_PASSIVE;

  count = 0;
  do {
    error = getaddrinfo((char *)hostname,
                        (char *)port,
                        &hints,
                        &local_res);
    count += 1;
    if (error == EAI_AGAIN) {
      if (debug) {
        fprintf(stderr,
		"%s: Sleeping on getaddrinfo EAI_AGAIN\n",
		__FUNCTION__);
        fflush(stderr);
      }
      sleep(1);
    }
  } while ((error == EAI_AGAIN) && (count <= 5));

  if (error) {
    if (debug) {

      fprintf(stderr,
	      "%s: could not resolve remote '%s' port '%s' af %d\n"
	      "\tgetaddrinfo returned %s (%d)\n",
	      __FUNCTION__,
	      hostname,
	      port,
	      af,
	      gai_strerror(error),
	      error);

    }
    return;
  }

  if (debug) {
    dump_addrinfo(stderr, local_res, hostname, port, af);
  }

  local_res_temp = local_res;

  while (local_res_temp != NULL) {

    temp_socket = socket(local_res_temp->ai_family,SOCK_STREAM,0);

    if (temp_socket == INVALID_SOCKET) {
      if (debug) {
	fprintf(stderr,
		"%s could not allocate a socket: %s (errno %d)\n",
		__FUNCTION__,
		strerror(errno),
		errno);
	fflush(stderr);
      }
      local_res_temp = local_res_temp->ai_next;
      continue;
    }

    /* happiness and joy, keep going */
    if (setsockopt(temp_socket,
		   SOL_SOCKET,
		   SO_REUSEADDR,
		   (char *)&on ,
		   sizeof(on)) == SOCKET_ERROR) {
      if (debug) {
	fprintf(stderr,
		"%s: warning: could not set SO_REUSEADDR: %s (errno %d)\n",
		__FUNCTION__,
		strerror(errno),
		errno);
	fflush(stderr);
      }
    }
    /* still happy and joyful */

    if ((bind(temp_socket,
	      local_res_temp->ai_addr,
	      local_res_temp->ai_addrlen) != SOCKET_ERROR) &&
	(listen(temp_socket,1024) != SOCKET_ERROR))  {

      /* OK, now add to the list */
      temp_elt = (struct listen_elt *)malloc(sizeof(struct listen_elt));
      if (temp_elt) {
	temp_elt->fd = temp_socket;
	if (listen_list) {
	  temp_elt->next = listen_list;
	}
	else {
	  temp_elt->next = NULL;
	}
	listen_list = temp_elt;
      }
      else {
	fprintf(stderr,
		"%s: could not malloc a listen_elt\n",
		__FUNCTION__);
	fflush(stderr);
	exit(1);
      }
    }
    else {
      /* we consider a bind() or listen() failure a transient and try
	 the next address */
      if (debug) {
	fprintf(stderr,
		"%s: warning: bind or listen call failure: %s (errno %d)\n",
		__FUNCTION__,
		strerror(errno),
		errno);
	fflush(stderr);
      }
      close(temp_socket);
    }
    local_res_temp = local_res_temp->ai_next;
  }

}