From 35f1fc325ea80370bb00e7cfcafe457ab6aca27c Mon Sep 17 00:00:00 2001
From: Andre Noll <maan@systemlinux.org>
Date: Sat, 12 Apr 2008 12:54:53 +0200
Subject: [PATCH] server: Introduce command_{pre,post}_select().

Also make listen_fd global, and annotate handle_connect() with
__noreturn.
---
 command.c |  17 +++------
 server.c  | 112 ++++++++++++++++++++++++++++++------------------------
 server.h  |   2 +-
 3 files changed, 69 insertions(+), 62 deletions(-)

diff --git a/command.c b/command.c
index 4eab9f65..b6c2de27 100644
--- a/command.c
+++ b/command.c
@@ -660,12 +660,10 @@ out:
 }
 
 /**
- * perform user authentication and execute a command
+ * Perform user authentication and execute a command.
  *
- * \param fd	    The file descriptor to send output to
- * \param peername  Identifies the connecting peer.
- *
- * \return EXIT_SUCCESS or EXIT_FAILURE
+ * \param fd The file descriptor to send output to.
+ * \param peername Identifies the connecting peer.
  *
  * Whenever para_server accepts an incoming tcp connection on
  * the port it listens on, it forks and the resulting child
@@ -688,7 +686,7 @@ out:
  *
  * \sa alarm(2), rc4(3), crypt.c, crypt.h
  */
-int handle_connect(int fd, const char *peername)
+__noreturn void handle_connect(int fd, const char *peername)
 {
 	int ret, argc, use_rc4 = 0;
 	char buf[4096];
@@ -799,15 +797,12 @@ int handle_connect(int fd, const char *peername)
 	PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name,
 			peername);
 	ret = cmd->handler(fd, argc, argv);
-	if (ret >= 0) {
-		ret = EXIT_SUCCESS;
+	if (ret >= 0)
 		goto out;
-	}
 err_out:
 	send_va_buffer(fd, "%s\n", para_strerror(-ret));
 net_err:
 	PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
-	ret = EXIT_FAILURE;
 out:
 	free(command);
 	free(argv);
@@ -816,5 +811,5 @@ out:
 		mmd->events++;
 	mmd->active_connections--;
 	mmd_unlock();
-	return ret;
+	exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
 }
diff --git a/server.c b/server.c
index 009c82a4..e793a9a7 100644
--- a/server.c
+++ b/server.c
@@ -114,6 +114,7 @@ char *user_list_file = NULL;
 static FILE *logfile;
 static int mmd_mutex, mmd_shm_id;
 static int signal_pipe;
+static int listen_fd;
 
 /**
  * para_server's log function
@@ -274,18 +275,18 @@ err:
 	exit(EXIT_FAILURE);
 }
 
-static unsigned init_network(void)
+static void init_network(void)
 {
-	int fd, ret = para_listen(AF_UNSPEC, IPPROTO_TCP, conf.port_arg);
+	int ret = para_listen(AF_UNSPEC, IPPROTO_TCP, conf.port_arg);
 
 	if (ret < 0)
 		goto err;
-	fd = ret;
-	ret = mark_fd_nonblocking(fd);
+	listen_fd = ret;
+	ret = mark_fd_nonblocking(listen_fd);
 	if (ret < 0)
 		goto err;
-	add_close_on_fork_list(fd); /* child doesn't need the listener */
-	return fd;
+	add_close_on_fork_list(listen_fd); /* child doesn't need the listener */
+	return;
 err:
 	PARA_EMERG_LOG("%s\n", para_strerror(-ret));
 	exit(EXIT_FAILURE);
@@ -349,10 +350,9 @@ static void init_afs(void)
 		(unsigned) afs_socket_cookie);
 }
 
-static unsigned server_init(int argc, char **argv)
+static void server_init(int argc, char **argv)
 {
 	/* connector's address information */
-	int sockfd;
 	struct server_cmdline_parser_params params = {
 		.override = 0,
 		.initialize = 1,
@@ -385,9 +385,8 @@ static unsigned server_init(int argc, char **argv)
 	mmd_lock();
 	/* init network socket */
 	PARA_NOTICE_LOG("initializing tcp command socket\n");
-	sockfd = init_network();
+	init_network();
 	PARA_NOTICE_LOG("server init complete\n");
-	return sockfd;
 }
 
 /*
@@ -439,6 +438,54 @@ static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds,
 	return ret;
 }
 
+static void command_pre_select(int *max_fileno, fd_set *rfds)
+{
+	para_fd_set(listen_fd, rfds, max_fileno);
+}
+
+static void command_post_select(fd_set *rfds)
+{
+	int new_fd, ret;
+	char *peer_name;
+	pid_t child_pid;
+
+	if (!FD_ISSET(listen_fd, rfds))
+		return;
+	ret = para_accept(listen_fd, NULL, 0);
+	if (ret < 0)
+		goto out;
+	new_fd = ret;
+	peer_name = remote_name(new_fd);
+	PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
+	mmd->num_connects++;
+	mmd->active_connections++;
+	random();
+	child_pid = fork();
+	if (child_pid < 0) {
+		ret = -ERRNO_TO_PARA_ERROR(errno);
+		goto out;
+	}
+	if (child_pid) {
+		close(new_fd);
+		/* parent keeps accepting connections */
+		return;
+	}
+	alarm(ALARM_TIMEOUT);
+	close_listed_fds();
+	para_signal_shutdown();
+	/*
+	 * put info on who we are serving into argv[0] to make
+	 * client ip visible in top/ps
+	 */
+//	for (i = argc - 1; i >= 0; i--)
+//		memset(argv[i], 0, strlen(argv[i]));
+//	sprintf(argv[0], "para_server (serving %s)", peer_name);
+	return handle_connect(new_fd, peer_name);
+out:
+	if (ret < 0)
+		PARA_CRIT_LOG("%s\n", para_strerror(-ret));
+}
+
 /**
  * the main function of para_server
  *
@@ -450,22 +497,17 @@ static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds,
  */
 int main(int argc, char *argv[])
 {
-	/* listen on sock_fd, new connection on new_fd */
-	int sockfd, new_fd;
-	char *peer_name;
-	int i, max_fileno, ret;
-	pid_t chld_pid;
+	int max_fileno, ret;
 	fd_set rfds, wfds;
 	struct timeval *timeout;
 
 	valid_fd_012();
-	sockfd = server_init(argc, argv);
+	server_init(argc, argv);
 repeat:
 	FD_ZERO(&rfds);
 	FD_ZERO(&wfds);
 	max_fileno = -1;
-	/* check socket and signal pipe in any case */
-	para_fd_set(sockfd, &rfds, &max_fileno);
+	command_pre_select(&max_fileno, &rfds);
 	para_fd_set(signal_pipe, &rfds, &max_fileno);
 	timeout = vss_preselect(&rfds, &wfds, &max_fileno);
 	server_select(max_fileno + 1, &rfds, &wfds, timeout);
@@ -502,36 +544,6 @@ genocide:
 			exit(EXIT_FAILURE);
 		}
 	}
-	if (!FD_ISSET(sockfd, &rfds))
-		goto repeat;
-
-	new_fd = para_accept(sockfd, NULL, 0);
-	if (new_fd < 0)
-		goto repeat;
-	peer_name = remote_name(new_fd);
-	PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
-	mmd->num_connects++;
-	mmd->active_connections++;
-	random();
-	chld_pid = fork();
-	if (chld_pid < 0) {
-		PARA_CRIT_LOG("fork failed\n");
-		goto repeat;
-	}
-	if (chld_pid) {
-		close(new_fd);
-		/* parent keeps accepting connections */
-		goto repeat;
-	}
-	alarm(ALARM_TIMEOUT);
-	close_listed_fds();
-	para_signal_shutdown();
-	/*
-	 * put info on who we are serving into argv[0] to make
-	 * client ip visible in top/ps
-	 */
-	for (i = argc - 1; i >= 0; i--)
-		memset(argv[i], 0, strlen(argv[i]));
-	sprintf(argv[0], "para_server (serving %s)", peer_name);
-	return handle_connect(new_fd, peer_name);
+	command_post_select(&rfds);
+	goto repeat;
 }
diff --git a/server.h b/server.h
index a5c6d3e1..73f27c78 100644
--- a/server.h
+++ b/server.h
@@ -108,6 +108,6 @@ extern struct server_args_info conf;
 /** Socket for afs-server communication. */
 extern int afs_socket;
 
-int handle_connect(int fd, const char *peername);
+__noreturn void handle_connect(int fd, const char *peername);
 void mmd_unlock(void);
 void mmd_lock(void);
-- 
2.39.5