Exemple #1
0
int start_server()
{
     int child_indx, pid, i, ctl_socket;
     int childs, freeservers, used, maxrequests, ret;
     char command_buffer[COMMANDS_BUFFER_SIZE];
     int user_informed = 0;

     ctl_socket = ci_named_pipe_create(CONF.COMMANDS_SOCKET);
     if (ctl_socket < 0) {
          ci_debug_printf(1,
                          "Error opening control socket %s. Fatal error, exiting!\n",
                          CONF.COMMANDS_SOCKET);
          exit(0);
     }

     if (!ci_proc_mutex_init(&accept_mutex)) {
          ci_debug_printf(1,
                          "Can't init mutex for accepting conenctions. Fatal error, exiting!\n");
          exit(0);
     }
     childs_queue = malloc(sizeof(struct childs_queue));
     if (!create_childs_queue(childs_queue, 2 * CONF.MAX_SERVERS)) {
          ci_proc_mutex_destroy(&accept_mutex);
          ci_debug_printf(1,
                          "Can't init shared memory. Fatal error, exiting!\n");
          exit(0);
     }

     init_commands();
     pid = 1;
#ifdef MULTICHILD
     if (CONF.START_SERVERS > CONF.MAX_SERVERS)
          CONF.START_SERVERS = CONF.MAX_SERVERS;

     for (i = 0; i < CONF.START_SERVERS; i++) {
          if (pid)
               pid = start_child(LISTEN_SOCKET);
     }
     if (pid != 0) {
          main_signals();

          while (1) {
               if ((ret = wait_for_commands(ctl_socket, command_buffer, 1)) > 0) {
                    ci_debug_printf(5, "I received the command: %s\n",
                                    command_buffer);
                    handle_monitor_process_commands(command_buffer);
               }
               if (ret < 0) {  /*Eof received on pipe. Going to reopen ... */
                    ci_named_pipe_close(ctl_socket);
                    ctl_socket = ci_named_pipe_open(CONF.COMMANDS_SOCKET);
                    if (ctl_socket < 0) {
                         ci_debug_printf(1,
                                         "Error opening control socket. We are unstable and going down!");
                         c_icap_going_to_term = 1;
                    }
               }

               if (c_icap_going_to_term)
                    break;
               childs_queue_stats(childs_queue, &childs, &freeservers, &used,
                                  &maxrequests);
               ci_debug_printf(10,
                               "Server stats: \n\t Children: %d\n\t Free servers: %d\n"
                               "\tUsed servers:%d\n\tRequests served:%d\n",
                               childs, freeservers, used, maxrequests);
               if (MAX_REQUESTS_PER_CHILD > 0 && (child_indx =
                                                  find_a_child_nrequests
                                                  (childs_queue,
                                                   MAX_REQUESTS_PER_CHILD)) >=
                   0) {
                    ci_debug_printf(8,
                                    "Max requests reached for child :%d of pid :%d\n",
                                    child_indx,
                                    childs_queue->childs[child_indx].pid);
                    pid = start_child(LISTEN_SOCKET);
                    //         usleep(500);
                    childs_queue->childs[child_indx].father_said = GRACEFULLY;
                    /*kill a server ... */
                    kill(childs_queue->childs[child_indx].pid, SIGTERM);

               }
               else if ((freeservers <= CONF.MIN_SPARE_THREADS && childs < CONF.MAX_SERVERS)
                        || childs < CONF.START_SERVERS) {
                    ci_debug_printf(8,
                                    "Free Servers: %d, children: %d. Going to start a child .....\n",
                                    freeservers, childs);
                    pid = start_child(LISTEN_SOCKET);
               }
               else if (freeservers >= CONF.MAX_SPARE_THREADS &&
                        childs > CONF.START_SERVERS &&
                        (freeservers - CONF.THREADS_PER_CHILD) > CONF.MIN_SPARE_THREADS) {

                    if ((child_indx = find_an_idle_child(childs_queue)) >= 0) {
                         childs_queue->childs[child_indx].father_said =
                             GRACEFULLY;
                         ci_debug_printf(8,
                                         "Free Servers: %d, children: %d. Going to stop child %d(index: %d)\n",
                                         freeservers, childs,
                                         childs_queue->childs[child_indx].pid,
                                         child_indx);
                         /*kill a server ... */
                         kill(childs_queue->childs[child_indx].pid, SIGTERM);
			 user_informed = 0;
                    }
               }
               else if (childs == CONF.MAX_SERVERS && freeservers < CONF.MIN_SPARE_THREADS) {
		 if(! user_informed) {
		         ci_debug_printf(1,
					 "ATTENTION!!!! Not enough available servers (children %d, free servers %d, used servers %d)!!!!! "
					 "Maybe you should increase the MaxServers and the "
					 "ThreadsPerChild values in c-icap.conf file!!!!!!!!!",childs , freeservers, used);
			 user_informed = 1;
		 }
               }
               if (c_icap_going_to_term)
                    break;
               check_for_exited_childs();
               if (c_icap_reconfigure) {
                    c_icap_reconfigure = 0;
                    if (!server_reconfigure()) {
			ci_debug_printf(1, "Error while reconfiguring, exiting!\n");
			 break;
		    }
               }
          }
          /*Main process exit point */
          ci_debug_printf(1,
                          "Possibly a term signal received. Monitor process going to term all children\n");
          kill_all_childs();
	  system_shutdown();
	  ci_debug_printf(1, "Exiting....\n");
          return 1;
     }
#else
     child_data = (child_shared_data_t *) malloc(sizeof(child_shared_data_t));
     child_data->pid = 0;
     child_data->freeservers = CONF.THREADS_PER_CHILD;
     child_data->usedservers = 0;
     child_data->requests = 0;
     child_data->connections = 0;
     child_data->to_be_killed = 0;
     child_data->father_said = 0;
     child_data->idle = 1;
     child_data->stats_size = ci_stat_memblock_size();
     child_data->stats = malloc(child_data->stats_size);
     child_data->stats->sig = MEMBLOCK_SIG;
     ci_stat_attach_mem(child_data->stats, child_data->stats_size, NULL);
     child_main(LISTEN_SOCKET, 0);
     ci_proc_mutex_destroy(&accept_mutex);
     destroy_childs_queue(childs_queue);
#endif
     return 1;
}
Exemple #2
0
int main(int argc, char **argv)
{
	/* Parse command line arguments. */
	int c = 0, li = 0;
	int daemonize = 0;
	const char *config_fn = CONF_DEFAULT_FILE;
	const char *config_db = NULL;
	const char *daemon_root = "/";

	/* Long options. */
	struct option opts[] = {
		{"config",    required_argument, 0, 'c' },
		{"confdb",    required_argument, 0, 'C' },
		{"daemonize", optional_argument, 0, 'd'},
		{"version",   no_argument,       0, 'V'},
		{"help",      no_argument,       0, 'h'},
		{0, 0, 0, 0}
	};

	while ((c = getopt_long(argc, argv, "c:C:dVh", opts, &li)) != -1) {
		switch (c) {
		case 'c':
			config_fn = optarg;
			break;
		case 'C':
			config_db = optarg;
			break;
		case 'd':
			daemonize = 1;
			if (optarg) {
				daemon_root = optarg;
			}
			break;
		case 'V':
			printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
			return EXIT_SUCCESS;
		case 'h':
		case '?':
			help();
			return EXIT_SUCCESS;
		default:
			help();
			return EXIT_FAILURE;
		}
	}

	/* Check for non-option parameters. */
	if (argc - optind > 0) {
		help();
		return EXIT_FAILURE;
	}

	/* Now check if we want to daemonize. */
	if (daemonize) {
		if (make_daemon(1, 0) != 0) {
			fprintf(stderr, "Daemonization failed, shutting down...\n");
			return EXIT_FAILURE;
		}
	}

	/* Clear file creation mask. */
	umask(0);

	/* Setup base signal handling. */
	setup_signals();

	/* Initialize cryptographic backend. */
	dnssec_crypto_init();
	atexit(dnssec_crypto_cleanup);

	/* Initialize pseudorandom number generator. */
	srand(time(NULL));

	/* POSIX 1003.1e capabilities. */
	setup_capabilities();

	/* Default logging to std out/err. */
	log_init();

	/* Open configuration. */
	conf_t *new_conf = NULL;
	if (config_db == NULL) {
		int ret = conf_new(&new_conf, conf_scheme, NULL);
		if (ret != KNOT_EOK) {
			log_fatal("failed to initialize configuration database "
			          "(%s)", knot_strerror(ret));
			log_close();
			return EXIT_FAILURE;
		}

		/* Import the configuration file. */
		ret = conf_import(new_conf, config_fn, true);
		if (ret != KNOT_EOK) {
			log_fatal("failed to load configuration file (%s)",
			          knot_strerror(ret));
			conf_free(new_conf, false);
			log_close();
			return EXIT_FAILURE;
		}

		new_conf->filename = strdup(config_fn);
	} else {
		/* Open configuration database. */
		int ret = conf_new(&new_conf, conf_scheme, config_db);
		if (ret != KNOT_EOK) {
			log_fatal("failed to open configuration database '%s' "
			          "(%s)", config_db, knot_strerror(ret));
			log_close();
			return EXIT_FAILURE;
		}
	}

	/* Run post-open config operations. */
	int res = conf_post_open(new_conf);
	if (res != KNOT_EOK) {
		log_fatal("failed to use configuration (%s)", knot_strerror(res));
		conf_free(new_conf, false);
		log_close();
		return EXIT_FAILURE;
	}

	conf_update(new_conf);

	/* Initialize logging subsystem. */
	log_reconfigure(conf(), NULL);

	/* Initialize server. */
	server_t server;
	res = server_init(&server, conf_bg_threads(conf()));
	if (res != KNOT_EOK) {
		log_fatal("failed to initialize server (%s)", knot_strerror(res));
		conf_free(conf(), false);
		log_close();
		return EXIT_FAILURE;
	}

	/* Reconfigure server interfaces.
	 * @note This MUST be done before we drop privileges. */
	server_reconfigure(conf(), &server);
	log_info("configured %zu zones", conf_id_count(conf(), C_ZONE));

	/* Alter privileges. */
	int uid, gid;
	if (conf_user(conf(), &uid, &gid) != KNOT_EOK ||
	    log_update_privileges(uid, gid) != KNOT_EOK ||
	    proc_update_privileges(uid, gid) != KNOT_EOK) {
		log_fatal("failed to drop privileges");
		server_deinit(&server);
		conf_free(conf(), false);
		log_close();
		return EXIT_FAILURE;
	}

	/* Check and create PID file. */
	long pid = (long)getpid();
	char *pidfile = NULL;
	if (daemonize) {
		pidfile = pid_check_and_create();
		if (pidfile == NULL) {
			server_deinit(&server);
			conf_free(conf(), false);
			log_close();
			return EXIT_FAILURE;
		}

		log_info("PID stored in '%s'", pidfile);
		if (chdir(daemon_root) != 0) {
			log_warning("failed to change working directory to %s",
			            daemon_root);
		} else {
			log_info("changed directory to %s", daemon_root);
		}
	}

	/* Now we're going multithreaded. */
	rcu_register_thread();

	/* Populate zone database. */
	log_info("loading zones");
	server_update_zones(conf(), &server);

	/* Check number of loaded zones. */
	if (knot_zonedb_size(server.zone_db) == 0) {
		log_warning("no zones loaded");
	}

	/* Start it up. */
	log_info("starting server");
	conf_val_t async_val = conf_get(conf(), C_SRV, C_ASYNC_START);
	res = server_start(&server, conf_bool(&async_val));
	if (res != KNOT_EOK) {
		log_fatal("failed to start server (%s)", knot_strerror(res));
		server_deinit(&server);
		rcu_unregister_thread();
		pid_cleanup(pidfile);
		log_close();
		conf_free(conf(), false);
		return EXIT_FAILURE;
	}

	if (daemonize) {
		log_info("server started as a daemon, PID %ld", pid);
	} else {
		log_info("server started in the foreground, PID %ld", pid);
		init_signal_started();
	}

	/* Start the event loop. */
	event_loop(&server);

	/* Teardown server and configuration. */
	server_deinit(&server);

	/* Free configuration. */
	conf_free(conf(), false);

	/* Unhook from RCU. */
	rcu_unregister_thread();

	/* Cleanup PID file. */
	pid_cleanup(pidfile);

	log_info("shutting down");
	log_close();

	return EXIT_SUCCESS;
}