Esempio n. 1
0
int main(int argc, char **argv)
{
	simple_worker *wp;
	int i;
#ifdef HAVE_SIGACTION
	struct sigaction sig_action;

	sig_action.sa_sigaction = NULL;
	sigfillset(&sig_action.sa_mask);
	sig_action.sa_flags=SA_NOCLDSTOP;
	sig_action.sa_handler = child_exited;
	sigaction(SIGCHLD, &sig_action, NULL);

	sig_action.sa_flags = SA_NODEFER|SA_RESTART;
	sig_action.sa_handler = sighandler;
	sigfillset(&sig_action.sa_mask);
	sigaction(SIGINT, &sig_action, NULL);
	sigaction(SIGPIPE, &sig_action, NULL);
#else /* HAVE_SIGACTION */

	signal(SIGINT, sighandler);
	signal(SIGPIPE, sighandler);
	signal(SIGCHLD, child_exited);
#endif /* HAVE_SIGACTION */

	iobs = iobroker_create();
	if (!iobs)
		die("Failed to create io broker set");

	for (i = 0; i < NWPS; i++) {
		wp = spawn_worker(print_some_crap, "lalala");
		if (!wp) {
			die("Failed to spawn worker(s)\n");
		}
		wps[i] = wp;
		printf("Registering worker sd %d with io broker\n", wp->sd);
		iobroker_register(iobs, wp->sd, wp, print_input);
	}

	iobroker_register(iobs, fileno(stdin), NULL, send_command);

	/* get to work */
	while (!sigreceived && iobroker_get_num_fds(iobs)) {
		iobroker_poll(iobs, -1);
	}

	for (i = 0; i < NWPS; i++) {
		kill(wps[i]->pid, SIGKILL);
	}

	return 0;
}
Esempio n. 2
0
File: net.c Progetto: op5/merlin
/*
 * This gets called when a connect() attempt has become writable.
 * It's entirely possible that the node we're trying to connect
 * to has connected to us while we were waiting for them, in
 * which case we need to figure out which of the two connections
 * we're supposed to use.
 */
static int conn_writable(int sd, int events, void *node_)
{
	merlin_node *node = (merlin_node *)node_;
	int result;
	int sel_sd;

	/* unregister so we don't peg one cpu at 100% */
	ldebug("CONN: In conn_writable(): node=%s; sd=%d; node->conn_sock=%d", node->name, sd, node->conn_sock);
	iobroker_unregister(nagios_iobs, sd);

	if (node->sock < 0) {
		/* no inbound connection accept()'ed yet */
		node->sock = sd;
		node->conn_sock = -1;
		if (!net_is_connected(node)) {
			node_disconnect(node, "Connection attempt failed: %s", strerror(errno));
			close(sd);
			return 0;
		}
		iobroker_register(nagios_iobs, sd, node, net_input);
		node_set_state(node, STATE_NEGOTIATING, "Connect completed successfully. Negotiating protocol");
		return 0;
	}

	sel_sd = net_negotiate_socket(node, node->conn_sock, node->sock);
	if (sel_sd < 0) {
		node_disconnect(node, "Failed to negotiate socket");
		return 0;
	}

	if (sel_sd == node->conn_sock) {
		iobroker_close(nagios_iobs, node->sock);
	} else if (sel_sd == node->sock) {
		iobroker_close(nagios_iobs, node->conn_sock);
	}

	node->sock = sel_sd;
	node->conn_sock = -1;
	node_set_state(node, STATE_NEGOTIATING, "polled for writability");
	/* now re-register for input */
	ldebug("IOB: registering %s(%d) for input events", node->name, node->sock);
	result = iobroker_register(nagios_iobs, node->sock, node, net_input);
	if (result < 0) {
		lerr("IOB: Failed to register %s(%d) for input events: %s",
		     node->name, node->sock, iobroker_strerror(result));
	}

	return 0;
}
Esempio n. 3
0
static int fd_start_cmd(child_process *cp)
{
	int pfd[2], pfderr[2];

	cp->outstd.fd = runcmd_open(cp->cmd, pfd, pfderr, NULL);
	if (cp->outstd.fd == -1) {
		return -1;
	}
	gettimeofday(&cp->start, NULL);

	cp->outerr.fd = pfderr[0];
	cp->pid = runcmd_pid(cp->outstd.fd);
	iobroker_register(iobs, cp->outstd.fd, cp, stdout_handler);
	iobroker_register(iobs, cp->outerr.fd, cp, stderr_handler);

	return 0;
}
Esempio n. 4
0
File: workers.c Progetto: atj/nagios
int init_workers(int desired_workers)
{
	worker_process **wps;
	int i;

	if (desired_workers <= 0) {
		desired_workers = 4;
	}

	if (workers_alive() == desired_workers)
		return 0;

	/* can't shrink the number of workers (yet) */
	if (desired_workers < num_workers)
		return -1;

	wps = calloc(desired_workers, sizeof(worker_process *));
	if (!wps)
		return -1;

	if (workers) {
		if (num_workers < desired_workers) {
			for (i = 0; i < num_workers; i++) {
				wps[i] = workers[i];
			}
		}

		free(workers);
	}

	workers = wps;
	for (i = 0; i < desired_workers; i++) {
		int ret;
		worker_process *wp;

		if (wps[i])
			continue;

		wp = spawn_worker(worker_init_func, (void *)get_global_macros());
		if (!wp) {
			logit(NSLOG_RUNTIME_WARNING, TRUE, "Failed to spawn worker: %s\n", strerror(errno));
			free_worker_memory(0);
			return ERROR;
		}
		set_socket_options(wp->sd, 256 * 1024);

		wps[i] = wp;
		ret = iobroker_register(nagios_iobs, wp->sd, wp, handle_worker_result);
		if (ret < 0) {
			printf("Failed to register worker socket with iobroker %p\n", nagios_iobs);
			exit(1);
		}
	}
	num_workers = desired_workers;

	logit(NSLOG_INFO_MESSAGE, TRUE, "Workers spawned: %d\n", num_workers);
	return 0;
}
Esempio n. 5
0
File: net.c Progetto: op5/merlin
/*
 * Accept an inbound connection from a remote host
 * Returns 0 on success and -1 on errors
 */
static int net_accept_one(int sd, int events, void *discard)
{
	int sock, result;
	merlin_node *node;
	struct sockaddr_in sain;
	socklen_t slen = sizeof(struct sockaddr_in);

	sock = accept(sd, (struct sockaddr *)&sain, &slen);
	if (sock < 0) {
		lerr("accept() failed: %s", strerror(errno));
		return -1;
	}

	node = find_node(&sain);
	linfo("NODESTATE: %s connected from %s:%d. Current state is %s",
		  node ? node->name : "An unregistered node",
		  inet_ntoa(sain.sin_addr), ntohs(sain.sin_port),
		  node ? node_state_name(node->state) : "unknown");
	if (!node) {
		close(sock);
		return 0;
	}

	switch (node->state) {
	case STATE_NEGOTIATING:
	case STATE_CONNECTED: case STATE_PENDING:
		/* if node->sock >= 0, we must negotiate which one to use */
		if (node->sock >= 0) {
			int sel_sd = net_negotiate_socket(node, node->sock, sock);
			if (sel_sd != sock) {
				close(sock);
			}
		}
		break;

	case STATE_NONE:
		/*
		 * we must close it unconditionally or we'll leak fd's
		 * for reconnecting nodes that were previously connected
		 */
		node_disconnect(node, "fd leak prevention for connecting nodes");
		node->sock = sock;
		break;

	default:
		lerr("%s %s has an unknown status", node_type(node), node->name);
		break;
	}

	node_set_state(node, STATE_NEGOTIATING, "Inbound connection accepted. Negotiating protocol version");
	result = iobroker_register(nagios_iobs, node->sock, node, net_input);
	if (result < 0) {
		lerr("IOB: Failed to register %d for %s node %s for input events: %s",
		     node->sock, node_type(node), node->name, iobroker_strerror(result));
	}

	return sock;
}
Esempio n. 6
0
int main(int argc, char **argv)
{
	int listen_fd, flags, sockopt = 1;
	struct sockaddr_in sain;
	int error;
	const char *err_msg;

	t_set_colors(0);
	t_start("iobroker ipc test");

	error = iobroker_get_max_fds(NULL);
	ok_int(error, IOBROKER_ENOSET, "test errors when passing null");

	err_msg = iobroker_strerror(error);
	test(err_msg && !strcmp(err_msg, iobroker_errors[(~error) + 1].string), "iobroker_strerror() returns the right string");

	iobs = iobroker_create();
	error = iobroker_get_max_fds(iobs);
	test(iobs && error >= 0, "max fd's for real iobroker set must be > 0");

	listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	flags = fcntl(listen_fd, F_GETFD);
	flags |= FD_CLOEXEC;
	fcntl(listen_fd, F_SETFD, flags);

	(void)setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));

	memset(&sain, 0, sizeof(sain));
	sain.sin_port = ntohs(9123);
	sain.sin_family = AF_INET;
	bind(listen_fd, (struct sockaddr *)&sain, sizeof(sain));
	listen(listen_fd, 128);
	iobroker_register(iobs, listen_fd, iobs, listen_handler);

	if (argc == 1)
		conn_spam(&sain);

	for (;;) {
		iobroker_poll(iobs, -1);
		if (iobroker_get_num_fds(iobs) <= 1) {
			break;
		}
	}

	iobroker_close(iobs, listen_fd);
	iobroker_destroy(iobs, 0);

	t_end();
	return 0;
}
Esempio n. 7
0
int qh_init(const char *path)
{
	int result, old_umask;

	if (qh_listen_sock >= 0)
		iobroker_close(nagios_iobs, qh_listen_sock);

	if (!path) {
		nm_log(NSLOG_RUNTIME_ERROR, "qh: query_socket is NULL. What voodoo is this?\n");
		return ERROR;
	}

	old_umask = umask(0117);
	errno = 0;
	qh_listen_sock = nsock_unix(path, NSOCK_TCP | NSOCK_UNLINK);
	umask(old_umask);
	if (qh_listen_sock < 0) {
		nm_log(NSLOG_RUNTIME_ERROR, "qh: Failed to init socket '%s'. %s: %s\n",
		       path, nsock_strerror(qh_listen_sock), strerror(errno));
		return ERROR;
	}

	/* plugins shouldn't have this socket */
	(void)fcntl(qh_listen_sock, F_SETFD, FD_CLOEXEC);

	/* most likely overkill, but it's small, so... */
	qh_table = g_hash_table_new_full(g_str_hash, g_str_equal,
					free, (GDestroyNotify) qh_remove);
	errno = 0;
	result = iobroker_register(nagios_iobs, qh_listen_sock, NULL, qh_registration_input);
	if (result < 0) {
		g_hash_table_destroy(qh_table);
		close(qh_listen_sock);
		nm_log(NSLOG_RUNTIME_ERROR, "qh: Failed to register socket with io broker: %s\n", iobroker_strerror(result));
		return ERROR;
	}

	nm_log(NSLOG_INFO_MESSAGE, "qh: Socket '%s' successfully initialized\n", path);

	/* now register our the in-core handlers */
	qh_register_handler("command", "Naemon external commands interface", 0, qh_command);
	qh_register_handler("echo", "The Echo Service - What You Put Is What You Get", 0, qh_echo);
	qh_register_handler("help", "Help for the query handler", 0, qh_help);

	return 0;
}
Esempio n. 8
0
static int qh_registration_input(int sd, int events, void *bq_)
{
	nm_bufferqueue *bq = (nm_bufferqueue *)bq_;
	struct sockaddr sa;
	socklen_t slen = 0;
	int nsd, result;

	memset(&sa, 0, sizeof(sa)); /* shut valgrind up */
	nsd = accept(sd, &sa, &slen);
	if (qh_max_running && qh_running >= qh_max_running) {
		nsock_printf(nsd, "503: Server full");
		close(nsd);
		return 0;
	}

	if (!(bq = nm_bufferqueue_create())) {
		nm_log(NSLOG_RUNTIME_ERROR, "qh: Failed to create iocache for inbound request\n");
		nsock_printf(nsd, "500: Internal server error");
		close(nsd);
		return 0;
	}

	/*
	 * @todo: Stash the iocache and the socket in some
	 * addressable list so we can release them on deinit
	 */
	result = iobroker_register(nagios_iobs, nsd, bq, qh_input);
	if (result < 0) {
		nm_log(NSLOG_RUNTIME_ERROR, "qh: Failed to register input socket %d with I/O broker: %s; errno=%d (%s)\n",
		       nsd, iobroker_strerror(result), errno, strerror(errno));
		nm_bufferqueue_destroy(bq);
		close(nsd);
		return 0;
	}

	/* make it non-blocking, but leave kernel buffers unchanged */
	worker_set_sockopts(nsd, 0);
	qh_running++;
	return 0;
}
Esempio n. 9
0
File: net.c Progetto: op5/merlin
/*
 * set up the listening socket (if applicable)
 */
int net_init(void)
{
	int result, sockopt = 1;
	struct sockaddr_in sain, inbound;
	struct sockaddr *sa = (struct sockaddr *)&sain;
	socklen_t addrlen = sizeof(inbound);

	if (!num_nodes)
		return 0;

	sain.sin_addr.s_addr = default_addr;
	sain.sin_port = htons(default_port);
	sain.sin_family = AF_INET;

	net_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (net_sock < 0)
		return -1;

	merlin_set_socket_options(net_sock, 0);

	/* if this fails we can do nothing but try anyway */
	(void)setsockopt(net_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int));

	result = bind(net_sock, sa, addrlen);
	if (result < 0)
		return -1;

	result = listen(net_sock, SOMAXCONN);
	if (result < 0)
		return -1;

	result = iobroker_register(nagios_iobs, net_sock, NULL, net_accept_one);
	if (result < 0) {
		lerr("IOB: Failed to register network socket with I/O broker: %s", iobroker_strerror(result));
		return -1;
	}

	return 0;
}
Esempio n. 10
0
static int conn_spam(struct sockaddr_in *sain)
{
	int i;

	signal(SIGALRM, (void (*)(int))sighandler);
	signal(SIGINT, (void (*)(int))sighandler);
	signal(SIGPIPE, SIG_IGN);
	alarm(20);

	for (i = 0; i < NUM_PROCS; i++) {
		int fd, sockopt = 1;

		fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		(void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
		proc_counter[i] = 0;
		iobroker_register(iobs, fd, (void *)&proc_counter[i], connected_handler);
		if (connect(fd, (struct sockaddr *)sain, sizeof(*sain))) {
			perror("connect");
		}
		iobroker_poll(iobs, -1);
	}
	return 0;
}
Esempio n. 11
0
static int listen_handler(int fd, int events, void *arg)
{
	int sock;
	struct sockaddr_in sain;
	socklen_t addrlen;

	if (!arg || arg != iobs) {
		printf("Argument passing seems to fail spectacularly\n");
	}

	addrlen = sizeof(sain);
	//printf("listen_handler(%d, %d, %p) called\n", fd, events, arg);
	sock = accept(fd, (struct sockaddr *)&sain, &addrlen);
	if (sock < 0) {
		perror("accept");
		return -1;
	}

	if (write(sock, msg[0], strlen(msg[0])) < 0)
		t_fail("write returned failure: %s", strerror(errno));
	iobroker_register(iobs, sock, iobs, echo_service);
	ok_int(iobroker_is_registered(iobs, sock), 1, "is_registered must be true");
	return 0;
}
Esempio n. 12
0
/* a service for registering workers */
static int register_worker(int sd, char *buf, unsigned int len)
{
	int i, is_global = 1;
	struct kvvec *info;
	struct wproc_worker *worker;

	logit(NSLOG_INFO_MESSAGE, TRUE, "wproc: Registry request: %s\n", buf);
	if (!(worker = calloc(1, sizeof(*worker)))) {
		logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to allocate worker: %s\n", strerror(errno));
		return 500;
	}

	info = buf2kvvec(buf, len, '=', ';', 0);
	if (info == NULL) {
		free(worker);
		logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: Failed to parse registration request\n");
		return 500;
	}

	worker->sd = sd;
	worker->ioc = iocache_create(1 * 1024 * 1024);

	iobroker_unregister(nagios_iobs, sd);
	iobroker_register(nagios_iobs, sd, worker, handle_worker_result);

	for(i = 0; i < info->kv_pairs; i++) {
		struct key_value *kv = &info->kv[i];
		if (!strcmp(kv->key, "name")) {
			worker->name = strdup(kv->value);
		}
		else if (!strcmp(kv->key, "pid")) {
			worker->pid = atoi(kv->value);
		}
		else if (!strcmp(kv->key, "max_jobs")) {
			worker->max_jobs = atoi(kv->value);
		}
		else if (!strcmp(kv->key, "plugin")) {
			struct wproc_list *command_handlers;
			is_global = 0;
			if (!(command_handlers = dkhash_get(specialized_workers, kv->value, NULL))) {
				command_handlers = calloc(1, sizeof(struct wproc_list));
				command_handlers->wps = calloc(1, sizeof(struct wproc_worker**));
				command_handlers->len = 1;
				command_handlers->wps[0] = worker;
				dkhash_insert(specialized_workers, strdup(kv->value), NULL, command_handlers);
			}
			else {
				command_handlers->len++;
				command_handlers->wps = realloc(command_handlers->wps, command_handlers->len * sizeof(struct wproc_worker**));
				command_handlers->wps[command_handlers->len - 1] = worker;
			}
			worker->wp_list = command_handlers;
		}
	}

	if (!worker->max_jobs) {
		/*
		 * each worker uses two filedescriptors per job, one to
		 * connect to the master and about 13 to handle libraries
		 * and memory allocation, so this guesstimate shouldn't
		 * be too far off (for local workers, at least).
		 */
		worker->max_jobs = (iobroker_max_usable_fds() / 2) - 50;
	}
	worker->jobs = fanout_create(worker->max_jobs);

	if (is_global) {
		workers.len++;
		workers.wps = realloc(workers.wps, workers.len * sizeof(struct wproc_worker *));
		workers.wps[workers.len - 1] = worker;
		worker->wp_list = &workers;
	}
	wproc_num_workers_online++;
	kvvec_destroy(info, 0);
	nsock_printf_nul(sd, "OK");

	/* signal query handler to release its iocache for this one */
	return QH_TAKEOVER;
}
Esempio n. 13
0
static void enter_worker(int sd)
{
	/* created with socketpair(), usually */
	master_sd = sd;
	parent_pid = getppid();
	(void)chdir("/tmp");
	(void)chdir("nagios-workers");

	if (setpgid(0, 0)) {
		/* XXX: handle error somehow, or maybe just ignore it */
	}

	/* we need to catch child signals the default way */
	signal(SIGCHLD, SIG_DFL);

	fcntl(fileno(stdout), F_SETFD, FD_CLOEXEC);
	fcntl(fileno(stderr), F_SETFD, FD_CLOEXEC);
	fcntl(master_sd, F_SETFD, FD_CLOEXEC);
	iobs = iobroker_create();
	if (!iobs) {
		/* XXX: handle this a bit better */
		worker_die("Worker failed to create io broker socket set");
	}

	/*
	 * Create a modest scheduling queue that will be
	 * more than enough for our needs
	 */
	sq = squeue_create(1024);
	set_socket_options(master_sd, 256 * 1024);

	iobroker_register(iobs, master_sd, NULL, receive_command);
	while (iobroker_get_num_fds(iobs) > 0) {
		int poll_time = -1;

		/* check for timed out jobs */
		for (;;) {
			child_process *cp;
			struct timeval now, tmo;

			/* stop when scheduling queue is empty */
			cp = (child_process *)squeue_peek(sq);
			if (!cp)
				break;

			tmo.tv_usec = cp->start.tv_usec;
			tmo.tv_sec = cp->start.tv_sec + cp->timeout;
			gettimeofday(&now, NULL);
			poll_time = tv_delta_msec(&now, &tmo);
			/*
			 * A little extra takes care of rounding errors and
			 * ensures we never kill a job before it times out.
			 * 5 milliseconds is enough to take care of that.
			 */
			poll_time += 5;
			if (poll_time > 0)
				break;

			/* this job timed out, so kill it */
			wlog("job with pid %d timed out. Killing it", cp->pid);
			kill_job(cp, ETIME);
		}

		iobroker_poll(iobs, poll_time);

		/*
		 * if our parent goes away we can't really do anything
		 * sensible at all, so let's just break out and exit
		 */
		if (kill(parent_pid, 0) < 0 && errno == ESRCH) {
			break;
		}
	}

	/* we exit when the master shuts us down */
	exit(EXIT_SUCCESS);
}