Beispiel #1
0
static int loop(int type)
{
	void (*workfn) (int ci);
	void (*deadfn) (int ci);
	int rv, i;

	rv = setup_config(type);
	if (rv < 0)
		goto fail;

	rv = setup_timer();
	if (rv < 0)
		goto fail;

	rv = setup_transport();
	if (rv < 0)
		goto fail;

	rv = setup_ticket();
	if (rv < 0)
		goto fail;

	rv = setup_listener(BOOTHC_SOCK_PATH);
	if (rv < 0)
		goto fail;
	client_add(rv, process_listener, NULL);

        while (1) {
                rv = poll(pollfd, client_maxi + 1, poll_timeout);
                if (rv == -1 && errno == EINTR)
                        continue;
                if (rv < 0) {
                        log_error("poll errno %d", errno);
			goto fail;
                }

                for (i = 0; i <= client_maxi; i++) {
                        if (client[i].fd < 0)
                                continue;
                        if (pollfd[i].revents & POLLIN) {
                                workfn = client[i].workfn;
                                if (workfn)
                                        workfn(i);
                        }
                        if (pollfd[i].revents &
			    (POLLERR | POLLHUP | POLLNVAL)) {
                                deadfn = client[i].deadfn;
                                if (deadfn)
                                        deadfn(i);
                        }
                }

		process_timerlist();
	}

	return 0;

fail:
	return -1;
}
Beispiel #2
0
static int
serve(lua_State* l)
{
    int port = luaL_checkint(l, 1);
    luaL_checktype(l, 2, LUA_TFUNCTION);

    if(port <= 0 || port > 65535) {
        return luaL_error(l, "port number must be within between 1 and 65535");
    }

    orka_server_t* server = malloc(sizeof(*server));
    server->port = port;
    server->lua = l;

    lua_pushvalue(l, 2);
    server->handler_ref = luaL_ref(l, LUA_REGISTRYINDEX);

    server->fd = setup_listener("0.0.0.0", server->port);
    if(server->fd < 0) {
        free(server);
        return orka_error(l, "setup_listener");
    }

    if(pthread_create(&server->thread, NULL, server_thread_main, server) < 0) {
        return orka_error(l, "pthread_create");
    }

    return 0;
}
Beispiel #3
0
static int setup(int type)
{
	int rv;

	rv = setup_config(type);
	if (rv < 0)
		goto fail;

	rv = setup_timer();
	if (rv < 0)
		goto fail;

	rv = setup_transport();
	if (rv < 0)
		goto fail;

	rv = setup_ticket();
	if (rv < 0)
		goto fail;

	rv = setup_listener(BOOTHC_SOCK_PATH);
	if (rv < 0)
		goto fail;
	client_add(rv, process_listener, NULL);

	return 0;

fail:
	return -1;
}
Beispiel #4
0
int _main(config_t *config) {
    pthread_t server_tid= 0;

    signal(SIGTERM, sig_handler);
    signal(SIGINT, sig_handler);
    signal(SIGPIPE, sig_handler);
    signal(SIGHUP, sig_handler);

    setproctitle("starting");

    s_listen = mallocz_or_die(sizeof(*s_listen));

    worker_pool_init_static(config);
    server_tid= setup_listener(config);
    graphite_worker= mallocz_or_die(sizeof(graphite_worker_t));
    pthread_create(&graphite_worker->tid, NULL, graphite_worker_thread, graphite_worker);

    for (;;) {
        int abort;

        abort= get_abort_val();
        if (abort & STOP) {
            break;
        }
        else
        if (abort & RELOAD) {
            if (config_reload(config)) {
                stop_listener(server_tid);
                server_tid= setup_listener(config);
                worker_pool_reload_static(config);
                /* XXX: check me */
                /* check and see if we need to stop the old graphite processor and replace it */
                graphite_worker_destroy(graphite_worker);
                pthread_create(&graphite_worker->tid, NULL, graphite_worker_thread, graphite_worker);
            }
            unset_abort_bits(RELOAD);
        }

        mark_second_elapsed();
        sleep(1);
    }
    final_shutdown(server_tid);
    SAY("bye");
    closelog();
    return(0);
}
Beispiel #5
0
int
main(int argc, char **argv)
{
	int	fd;
	int	nfd;
	int	c;
 
        /* process arguments */
	while ((c = getopt(argc, argv, POS "d")) != -1) {
		switch (c) {
		case 'd':
			debug = 1;
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 2)
		usage();

	fd = setup_listener(atoi(argv[0]));
	if (fd == -1)
		exit(1);

	/* don't bother reaping, this is a test program... */
	signal(SIGCHLD, SIG_IGN);

	for (;;) {
		pid_t	kid;

		nfd = accept(fd, NULL, NULL);

		kid = fork();
		switch (kid) {
		case -1:
			/* XXXrcd: error. */
			close(nfd);
			fprintf(stderr, "fork: %s\n", strerror(errno));
			break;
		case 0:
			close(fd);
			serve_file(nfd, argv[1]);
			exit(0);
		default:
			close(nfd);
			break;
		}
	}
}
Beispiel #6
0
int main(int argc, char *argv[]) {
  cfg.prog = argv[0];
  cfg.prog=argv[0];
  cfg.pid = getpid();
  int n, signo, opt, *fd;
  siginfo_t info;
  utarray_new(cfg.fds,&ut_int_icd);

  while ( (opt=getopt(argc,argv,"vp:a:h")) != -1) {
    switch(opt) {
      case 'v': cfg.verbose++; break;
      case 'p': cfg.port=atoi(optarg); break; 
      case 'a': cfg.addr=inet_addr(optarg); break; 
      case 'h': default: usage(); break;
    }
  }
  if (cfg.addr == INADDR_NONE) usage();
  if (cfg.port==0) usage();

  /* block all signals. we only take signals synchronously in sigwaitinfo */
  sigset_t all;
  sigfillset(&all);
  sigprocmask(SIG_SETMASK,&all,NULL);

  /* make a set of the signals we accept in sigwaitinfo. others blocked */
  sigset_t sw;
  sigemptyset(&sw);
  for(n=0; n < sizeof(sigs)/sizeof(*sigs); n++) sigaddset(&sw, sigs[n]);

  if (setup_listener()) goto done;

  alarm(1);
  while ( (signo = sigwaitinfo(&sw, &info)) > 0) {
    switch (signo) {
      case SIGALRM: if ((++cfg.ticks % 10) == 0) periodic(); alarm(1); break;
      case SIGIO:   service_network();                                 break;
      default:     printf("got signal %d\n", signo);                   goto done;
    }
  }

done:
  fd=NULL;
  while ( (fd=(int*)utarray_next(cfg.fds,fd))) close(*fd);
  utarray_free(cfg.fds);
  return 0;
}
Beispiel #7
0
int main(int argc, char **argv){
	if(argc != 3){
		printf("Usage: rfss mode<s|c> port\n");
		exit(1);
	}
	if(strcmp(argv[1],"c")==0)
		set_mode(CLIENT);
	else if(strcmp(argv[1],"s")==0)
		set_mode(SERVER);
	else{
		printf("Invalid mode: mode can take value of s or c only\n");
		exit(1);
	}
	char *endptr;
	int port = (int) strtol(argv[2], &endptr, 10);
	if(*endptr != 0){
		printf("Invalid port\n");
		exit(1);
	}
	setup_listener(port);
	setbuf(stdout, NULL);
	rfss_process_command();
}
Beispiel #8
0
static void run_listener(const char* fifo, const guint16 port, const char* proto_name)
{
	struct sockaddr_in clientaddr;
	int clientlen = sizeof(clientaddr);
	socket_handle_t sock;
	char* buf;
	ssize_t buflen;
	FILE* fp = NULL;

	if (signal(SIGINT, exit_from_loop) == SIG_ERR) {
		g_warning("Can't set signal handler");
		return;
	}

	if (setup_dumpfile(fifo, &fp) == EXIT_FAILURE) {
		if (fp)
			fclose(fp);
		return;
	}

	if (setup_listener(port, &sock) == EXIT_FAILURE)
		return;

	g_debug("Listener running on port %u", port);

	buf = (char*)g_malloc(PKT_BUF_SIZE);
	while(run_loop == TRUE) {
		memset(buf, 0x0, PKT_BUF_SIZE);

		buflen = recvfrom(sock, buf, PKT_BUF_SIZE, 0, (struct sockaddr *)&clientaddr, &clientlen);
		if (buflen < 0) {
			switch(errno) {
				case EAGAIN:
				case EINTR:
					break;
				default:
#ifdef _WIN32
					{
						wchar_t *errmsg = NULL;
						int err = WSAGetLastError();
						FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
							NULL, err,
							MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
							(LPWSTR)&errmsg, 0, NULL);
						g_warning("Error in recvfrom: %S (err=%d)", errmsg, err);
						LocalFree(errmsg);
					}
#else
					g_warning("Error in recvfrom: %s (errno=%d)", strerror(errno), errno);
#endif
					run_loop = FALSE;
					break;
			}
		} else {
			if (dump_packet(proto_name, port, buf, buflen, clientaddr, fp) == EXIT_FAILURE)
				run_loop = FALSE;
		}
	}

	fclose(fp);
	closesocket(sock);
	g_free(buf);
}
Beispiel #9
0
int main(int argc, char **argv)
{
  char *user, *group, *interface, *root, *port, *cmd;
  int niceinc;
  int nofork;
  int timeout;
  int instances;
  int queue;

  int reuse;
  int keepalive;
  int what;
  int value;
  int offset;
  int i, j;
  char c;
  int lfd;
  int nfd;
  struct sigaction sag;
  sigset_t sst;
  int status;
  int hang;
  int busy;
  int tos;
  int ttl;
  int sane;
  int just;
#ifdef USE_IDSA
  int exitcode;
  int killcode;
  int flags;
  unsigned int arisk, crisk, irisk, risk;
#endif

  double limit_load = 0.0;

  port = NULL;
  user = NULL;
  group = NULL;
  root = NULL;
  interface = NULL;
  cmd = NULL;

  just = 0;
  sane = 1;
  reuse = 1;
  keepalive = 1;
  niceinc = 0;
  nofork = 0;
  timeout = 0;
  instances = 0;
  queue = 5;
  tos = 0;
  ttl = 0;
  offset = 0;

#ifdef USE_IDSA
  flags = 0;
  arisk = idsa_risk_make(-0.3,0.8);
  crisk = IDSA_R_UNKNOWN;
  irisk = IDSA_R_PARTIAL;
#endif

  i = j = 1;
  while (i < argc) {
    if (argv[i][0] == '-') {
      c = argv[i][j];
      switch (c) {
      case 'c':
	printf("(c) 2002,2007 Marc Welz: Distributed under the terms of the GNU General Public License\n");
	exit(0);
	break;
      case 'h':		/* print brief help message */
      case '?':
	usage(argv[0]);
	exit(0);
	break;
      case 'v':
#ifdef USE_IDSA
	printf("linetd %s-i\n", VERSION);
#else
	printf("linetd %s\n", VERSION);
#endif
	exit(0);
	break;

	/* flags */
      case 'f':		/* keep in foreground */
	nofork = 1;
	j++;
	break;
      case 'a' :        /* disable reuse of address */
        j++;
	c = argv[i][j];
	switch (c) {
        case 'r':
          reuse = 0;
          break;
	case 'k':
          keepalive = 0;
          break;
	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -a requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -a%c", c);
	  break;
        }

	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}

        break;
      case 'd' :        /* disable sanity checks */
        sane = 0;
	j++;
        break;

	/* strings */
      case 'u':
      case 'g':
      case 'p':
      case 'r':
      case 'b':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	switch (c) {
	case 'u':
	  user = argv[i] + j;
	  break;
	case 'g':
	  group = argv[i] + j;
	  break;
	case 'p':        
	  port = argv[i] + j;
	  break;
	case 'r':
	  root = argv[i] + j;
	  break;
	case 'b':
	  interface = argv[i] + j;
	  break;
	}
	i++;
	j = 1;
	break;

      case 'l':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a floating point value", c);
	}
        load_fd = open(LOADAVG, O_RDONLY);
        if(load_fd < 0){
          fatal_failure(LINET_SYSTEM, errno, "unable to open %s to read load average", LOADAVG);
        }
	limit_load = atof(argv[i] + j);
	i++;
	j = 1;
	break;

      case 'n':
      case 'm':
      case 'i':
      case 'j':
      case 'q':
      case 't':
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}
	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -%c requires a numeric value", c);
	}
	value = atoi(argv[i] + j);
	switch (c) {
	case 'n':
	  niceinc = value;
	  break;
	case 'm':
	  timeout = value;
	  break;
	case 'i':
	  instances = value;
	  break;
	case 'j':
	  just = value;
	  break;
	case 'q':
	  queue = value;
	  break;
	case 't':
	  ttl = value;
	  break;
	}
	i++;
	j = 1;
	break;

      case 'o':
        j++;
	c = argv[i][j];
	switch (c) {
        case 'c':
          tos = IPTOS_LOWCOST;
          break;
	case 'd':
          tos = IPTOS_LOWDELAY;
          break;
	case 'r':
          tos = IPTOS_RELIABILITY;
          break;
	case 't':
          tos = IPTOS_THROUGHPUT;
          break;

	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -o requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -o%c", c);
	  break;
        }

	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}

        break;

#ifdef USE_IDSA
      case 'k' : /* risk ratings */
	j++;
	c = argv[i][j];
	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}

	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -k%c requires a parameter", c);
	}

        risk = idsa_risk_parse(argv[i]+j);

	switch (c) {
	case 'a':
          arisk = risk;
          break;
	case 'c':
          crisk = risk;
          break;
	case 'i':
          irisk = risk;
          break;
        }
	i++;
	j = 1;
        break;

      case 'x':
        j++;
	c = argv[i][j];
	switch (c) {
        case 'e':
	  flags |= IDSA_F_ENV; /* honour IDSA_SOCKET */
          break;
	case 'o':
	  flags |= IDSA_F_FAILOPEN; /* continue on failure */
          break;
	case 'u':
	  flags |= IDSA_F_UPLOAD; /* allow uploading of rules */
          break;
	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -x requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -x%c", c);
	  break;
        }
	j++;
	if (argv[i][j] == '\0') {
	  j = 1;
	  i++;
	}
        break;
#endif

      case 's':
	j++;
	c = argv[i][j];
	what = 0;
	switch (c) {
	case 'c':
	  what = RLIMIT_CORE;
	  break;
	case 'd':
	  what = RLIMIT_DATA;
	  break;
	case 'f':
	  what = RLIMIT_FSIZE;
	  break;
	case 'l':
	  what = RLIMIT_MEMLOCK;
	  break;
	case 'm':
	  what = RLIMIT_RSS;
	  break;
	case 'n':
	  what = RLIMIT_NOFILE;
	  break;
	case 's':
	  what = RLIMIT_STACK;
	  break;
	case 't':
	  what = RLIMIT_CPU;
	  break;
	case 'u':
	  what = RLIMIT_NPROC;
	  break;
	case 'v':
	  what = RLIMIT_AS;
	  break;

	case '\0':
	  fatal_failure(LINET_USAGE, 0, "option -s requires a modifier");
	  break;
	default:
	  fatal_failure(LINET_USAGE, 0, "unknown modifier -s%c", c);
	  break;
	}

	j++;
	if (argv[i][j] == '\0') {
	  j = 0;
	  i++;
	}

	if (i >= argc) {
	  fatal_failure(LINET_USAGE, 0, "option -s%c requires a parameter", c);
	}
	if (!isdigit(argv[i][j])) {
	  fatal_failure(LINET_USAGE, 0, "option -s%c requires a numeric value", c);
	}
	value = atoi(argv[i] + j);

        if(resource_count >= LINET_MAXRES){
	  fatal_failure(LINET_USAGE, 0, "too many resource restrictions", c);
        }

        resource_table[resource_count][0] = what;
        resource_table[resource_count][1] = value;
        resource_count++;

	i++;
	j = 1;
	break;

      case '-':
	j++;
	break;
      case '\0':
	j = 1;
	i++;
	break;
      default:
	fatal_failure(LINET_USAGE, 0, "unknown option -%c", argv[i][j]);
	break;
      }
    } else {
      cmd = argv[i];
      offset = i + 1;

      if (sane) {
        if (i + 1 >= argc){
          fprintf(stderr, "%s: warning: zeroth argument should be specified\n", argv[0]);
          offset = i;
        }
      }

      i = argc;
    }
  }

  if (cmd == NULL) {
    fatal_failure(LINET_USAGE, 0, "require a command to run");
  }

  if (!nofork) {
    fork_parent(argv[0]);
  }
#ifdef USE_IDSA
  if (ic == NULL) {
    ic = idsa_open(LINETD, NULL, flags);
  }
  if (ic == NULL) {
    fprintf(stderr, "%s: unable to open idsa connection\n", argv[0]);
    exit(EX_UNAVAILABLE);
  }
#endif

  sigfillset(&(sag.sa_mask));
  sag.sa_flags = 0;

  sag.sa_handler = handle_child;
  if (sigaction(SIGCHLD, &sag, NULL)) {
    fatal_failure(LINET_SYSTEM, errno, "unable to set signal handler");
  }

  sag.sa_handler = handle_stop;
  if (sigaction(SIGTERM, &sag, NULL)) {
    fatal_failure(LINET_SYSTEM, errno, "unable to set signal handler");
  }

  lfd = setup_listener(argv[0], port, interface, queue, ttl, tos, reuse, keepalive);

  drop_root(argv[0], user, group, root);

  if(sane){
    if(access(cmd, X_OK)){
      fatal_failure(LINET_SYSTEM, errno, "\"%s\" %s", cmd, (cmd[0] == '/') ? "appears unavailable" : "might need an absolute path");
    }
  }

  if (niceinc) {
    nice(niceinc);
  }

#ifdef USE_IDSA
  if(idsa_set(ic, LINET_DR, LINET_SCHEME, 1, IDSA_R_SUCCESS, IDSA_R_UNKNOWN, IDSA_R_UNKNOWN, 
        IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SSTART, 
        "version", IDSA_T_STRING, VERSION, 
        NULL) != IDSA_L_ALLOW){
    fprintf(stderr, "%s: start disallowed\n", LINETD);
    return EX_NOPERM;
  }
#endif

  if (!nofork) {
    close(STDERR_FILENO);
  }

  sigemptyset(&sst);
  sigaddset(&sst, SIGCHLD);
  sigaddset(&sst, SIGTERM);

  sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child signal for everything execpt accept and sleep */

  while (run) {
#ifdef USE_IDSA
    nfd = accept_connection(lfd, arisk, crisk, irisk);
#else
    nfd = accept_connection(lfd);
#endif
    if (nfd >= 0) {
      run_command(lfd, cmd, &argv[offset], nfd, timeout);
      if(just){
        just--;
        if(just == 0){
          run = 0;
        }
      }
    }

    do{ /* check children and load */
      busy = 0;
      hang = ((instances > 0) && (child_count >= instances)); /* actually wait for child */

      if (zombies || hang) {
        if (waitpid(WAIT_ANY, &status, hang ? 0 : WNOHANG) > 0) {	/* collect pids without risk of EINTR */
#ifdef USE_IDSA

          /* in theory this could parse signals and exit codes. Eg SIG{SEGV,BUS} == ES_INTERNAL etc */

          if (WIFEXITED(status)) {
            exitcode = WEXITSTATUS(status);
            if (exitcode == 0) {
              idsa_set(ic, LINET_JD, LINET_SCHEME, 0, IDSA_R_NONE, IDSA_R_UNKNOWN, IDSA_R_UNKNOWN, 
                  IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WSTOP, 
                  NULL);
            } else {
              idsa_set(ic, LINET_JE, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL, 
                  IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WFAIL, 
                  IDSA_ES,  IDSA_T_STRING, IDSA_ES_OTHER, 
                  "exit",   IDSA_T_INT, &exitcode, 
                  NULL);
            }
          } else if (WIFSIGNALED(status)) {
            killcode = WTERMSIG(status);
            idsa_set(ic, LINET_JS, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL,
                IDSA_SSM, IDSA_T_STRING, IDSA_SSM_WFAIL, 
                IDSA_ES,  IDSA_T_STRING, IDSA_ES_OTHER, 
                "signal", IDSA_T_INT, &killcode,
                NULL);
          }
#endif
          child_count--;
          busy = ! hang; 
        } else { /* nothing more to collect */
          zombies = 0;
        }
      }

      if((load_fd >= 0) && (zombies == 0)){ /* if zombies then loop will run again, defer load check */
        if(get_load() > limit_load){ /* go to sleep if overloaded */
          sigprocmask(SIG_UNBLOCK, &sst, NULL);	/* enable child|term signal */
          sleep(LINET_SLEEP);
          sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child|term signal */
          busy = run;
        }
      }
    } while (busy); /* end of child and delay loop */
  } /* end of main loop */

  if(lfd >= 0){
    close(lfd);
  }
  if(load_fd >= 0){
    close(load_fd);
  }

#ifdef USE_IDSA
  idsa_set(ic, LINET_DE, LINET_SCHEME, 0, IDSA_R_TOTAL, IDSA_R_NONE, IDSA_R_UNKNOWN, 
      IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SSTOP, 
      "version", IDSA_T_STRING, VERSION, 
      NULL);
  idsa_close(ic);
#endif

  return 0;
}
Beispiel #10
0
/* process client requests */
int
srv_loop( const char* ipaddr, int port,
             const char* mcast_addr )
{
    int                 rc, maxfd, err, nrdy, i;
    fd_set              rset;
    struct timeval      tmout, idle_tmout, *ptmout = NULL;
    tmfd_t              *asock = NULL;
    size_t              n = 0, nasock = 0, max_nasock = LQ_BACKLOG;
    sigset_t            oset, bset;

    static const long IDLE_TMOUT_SEC = 30;

    assert( (port > 0) && mcast_addr && ipaddr );

    (void)tmfprintf( g_flog, "Server is starting up, max clients = [%u]\n",
                        g_uopt.max_clients );
    asock = calloc (max_nasock, sizeof(*asock));
    if (!asock) {
        mperror (g_flog, ENOMEM, "%s: calloc", __func__);
        return ERR_INTERNAL;
    }

    init_server_ctx( &g_srv, g_uopt.max_clients,
            (ipaddr[0] ? ipaddr : "0.0.0.0") , (uint16_t)port, mcast_addr );

    g_srv.rcv_tmout = (u_short)g_uopt.rcv_tmout;
    g_srv.snd_tmout = RLY_SOCK_TIMEOUT;

    /* NB: server socket is non-blocking! */
    if( 0 != (rc = setup_listener( ipaddr, port, &g_srv.lsockfd,
            g_uopt.lq_backlog )) ) {
        return rc;
    }

    sigemptyset (&bset);
    sigaddset (&bset, SIGINT);
    sigaddset (&bset, SIGQUIT);
    sigaddset (&bset, SIGCHLD);
    sigaddset (&bset, SIGTERM);

    (void) sigprocmask (SIG_BLOCK, &bset, &oset);

    TRACE( (void)tmfprintf( g_flog, "Entering server loop [%s]\n",
        SLOOP_TAG) );
    while (1) {
        FD_ZERO( &rset );
        FD_SET( g_srv.lsockfd, &rset );
        FD_SET( g_srv.cpipe[0], &rset );

        maxfd = (g_srv.lsockfd > g_srv.cpipe[0] ) ? g_srv.lsockfd : g_srv.cpipe[0];
        for (i = 0; (size_t)i < nasock; ++i) {
            assert (asock[i].fd >= 0);
            FD_SET (asock[i].fd, &rset);
            if (asock[i].fd > maxfd) maxfd = asock[i].fd;
        }

        /* if there are accepted sockets - apply specified time-out
         */
        tmout.tv_sec = g_uopt.ssel_tmout;
        tmout.tv_usec = 0;

        idle_tmout.tv_sec = IDLE_TMOUT_SEC;
        idle_tmout.tv_usec = 0;

        /* enforce *idle* select(2) timeout to alleviate signal contention */
        ptmout = ((nasock > 0) && (g_uopt.ssel_tmout > 0)) ? &tmout : &idle_tmout;

        TRACE( (void)tmfprintf( g_flog, "Waiting for input from [%ld] fd's, "
            "%s timeout\n", (long)(2 + nasock), (ptmout ? "with" : "NO")));

        if (ptmout && ptmout->tv_sec) {
            TRACE( (void)tmfprintf (g_flog, "select() timeout set to "
            "[%ld] seconds\n", ptmout->tv_sec) );
        }

        (void) sigprocmask (SIG_UNBLOCK, &bset, NULL);
        if( must_quit() ) {
            TRACE( (void)tmfputs( "Must quit now\n", g_flog ) );
            rc = 0; break;
        }

        nrdy = select (maxfd + 1, &rset, NULL, NULL, ptmout);
        err = errno;
        (void) sigprocmask (SIG_BLOCK, &bset, NULL);

        if( must_quit() ) {
            TRACE( (void)tmfputs( "Must quit now\n", g_flog ) );
            rc = 0; break;
        }
        wait_terminated( &g_srv );

        if( nrdy < 0 ) {
            if (EINTR == err) {
                TRACE( (void)tmfputs ("INTERRUPTED, yet "
                        "will continue.\n", g_flog)  );
                rc = 0; continue;
            }

            mperror( g_flog, err, "%s: select", __func__ );
            break;
        }

        TRACE( (void)tmfprintf (g_flog, "Got %ld requests\n", (long)nrdy) );
        if (0 == nrdy) {    /* time-out */
            tmout_requests (asock, &nasock);
            rc = 0; continue;
        }

        if( FD_ISSET(g_srv.cpipe[0], &rset) ) {
            (void) tpstat_read( &g_srv );
            if (--nrdy <= 0) continue;
        }

        if ((0 < nasock) &&
                 (0 < (nrdy - (FD_ISSET(g_srv.lsockfd, &rset) ? 1 : 0)))) {
            process_requests (asock, &nasock, &rset, &g_srv);
            /* n now contains # (yet) unprocessed accepted sockets */
        }

        if (FD_ISSET(g_srv.lsockfd, &rset)) {
            if (nasock >= max_nasock) {
                (void) tmfprintf (g_flog, "Cannot accept sockets beyond "
                    "the limit [%ld/%ld], skipping\n",
                    (long)nasock, (long)max_nasock);
            }
            else {
                n = max_nasock - nasock; /* append asock */
                accept_requests (g_srv.lsockfd, &(asock[nasock]), &n);
                nasock += n;
            }
        }
    } /* server loop */

    TRACE( (void)tmfprintf( g_flog, "Exited server loop [%s]\n", SLOOP_TAG) );

    for (i = 0; (size_t)i < nasock; ++i) {
        if (asock[i].fd > 0) (void) close (asock[i].fd);
    }
    free (asock);

    /* receive additional (blocked signals) */
    (void) sigprocmask (SIG_SETMASK, &oset, NULL);
    wait_terminated( &g_srv );
    terminate_all_clients( &g_srv );
    wait_all( &g_srv );

    if (0 != close( g_srv.lsockfd )) {
        mperror (g_flog, errno, "server socket close");
    }

    free_server_ctx( &g_srv );

    (void)tmfprintf( g_flog, "Server exits with rc=[%d]\n", rc );
    return rc;
}
Beispiel #11
0
/**
 * Main server event loop.
 */
static int
child (const int8_t index, const uint8_t *server_port)
{
    int                         listensock,
                                epollfd;

    struct epoll_event          event,
                                *events;


    /* setup listen socket */
    if ((listensock = setup_listener (server_port)) < 0) {
        err (1, "Could not setup listen socket");
    }

    fprintf (stdout, "proc %d: Listening on port %s...\n",
             index, (char *) server_port);

    /* initialize cache */
    if (cache_init ((const uint8_t *) CACHE_BASEDIR) < 0) {
        err (1, "Could not create cache dir");
    }
    fprintf (stdout, "proc %d: Initialized cache...\n", index);

    /* initialize epoll */
    if ((epollfd = epoll_create1 (0)) < 0) {
        err (1, "Could not initialize epoll");
    }

    /* add epoll event for handling listen socket */
    struct command *lcmd = calloc (1, sizeof (struct command));
    lcmd->cfd = listensock;
    epoll_add (epollfd, lcmd);

    /* event buffer */
    events = calloc (MAXEVENTS, sizeof (event));

    fprintf (stdout, "proc %d: Entering main loop...\n", index);
    for (;;) {
        /* block until we get some events to process */
        int numevents = epoll_wait (epollfd, events, MAXEVENTS, -1);
        struct command *command;

        /* process all events */
        for (int i = 0; i < numevents; i++) {
            /* get command */
            command = events[i].data.ptr;

            /* epoll error */
            if ((events[i].events & EPOLLERR) ||
                (events[i].events & EPOLLHUP) ||
                (!(events[i].events & EPOLLIN)))
            {
                /* notified but nothing ready for processing */
                warn ("epoll error");
                close (command->cfd);
                close (command->rfd);
                continue;
            }
            /* ACCEPT */
            else if (command->cfd == listensock) {
                do_accept (listensock, epollfd);
                /* processed all incoming events on listensock, continue to
                 * next event. */
                continue;
            }
            /* HANDLE COMMANDS */
            else {
                switch (command->cmd) {
                    case READ_CMD:
                        do_read_cmd (epollfd, command);
                        break;

                    case READ_REMOTE:
                        ;   /* hack needed for variable defs inside switch */
                        uint8_t buf[BUFLEN] = { 0 };
                        ssize_t buflen;
                        /* command is free'd in d_r_r() */
                        int cfd = command->cfd;

                        do_read_remote (command, buf, &buflen);
                        /* verify that we actually have data to relay back */
                        if (buflen > 0) {
                            if (!sendall (cfd, buf, (size_t *) &buflen)) {
                                warn ("Could not relay back data to client");
                            }
                        }
                        break;

                    default:
                        break;
                }
            }
        }
    }

    free (events);
    close (listensock);

    return EXIT_SUCCESS;
}