+static void command_pre_select(struct sched *s, struct task *t)
+{
+ struct server_command_task *sct = container_of(t, struct server_command_task, task);
+ para_fd_set(sct->listen_fd, &s->rfds, &s->max_fileno);
+}
+
+static int command_post_select(struct sched *s, struct task *t)
+{
+ struct server_command_task *sct = container_of(t, struct server_command_task, task);
+
+ int new_fd, ret, i;
+ char *peer_name;
+ pid_t child_pid;
+ uint32_t *chunk_table;
+
+ ret = para_accept(sct->listen_fd, &s->rfds, NULL, 0, &new_fd);
+ if (ret <= 0)
+ goto out;
+ peer_name = remote_name(new_fd);
+ PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
+ mmd->num_connects++;
+ mmd->active_connections++;
+ /*
+ * The chunk table is a pointer located in the mmd struct that points
+ * to dynamically allocated memory, i.e. it must be freed by the parent
+ * and the child. However, as the mmd struct is in a shared memory
+ * area, there's no guarantee that after the fork this pointer is still
+ * valid in child context. As it is not used in the child anyway, we
+ * save it to a local variable before the fork and free the memory via
+ * that copy in the child directly after the fork.
+ */
+ chunk_table = mmd->afd.afhi.chunk_table;
+ child_pid = fork();
+ if (child_pid < 0) {
+ ret = -ERRNO_TO_PARA_ERROR(errno);
+ goto out;
+ }
+ if (child_pid) {
+ /* avoid problems with non-fork-safe PRNGs */
+ unsigned char buf[16];
+ get_random_bytes_or_die(buf, sizeof(buf));
+ close(new_fd);
+ /* parent keeps accepting connections */
+ return 0;
+ }
+ /* mmd might already have changed at this point */
+ free(chunk_table);
+ 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 = sct->argc - 1; i >= 0; i--)
+ memset(sct->argv[i], 0, strlen(sct->argv[i]));
+ sprintf(sct->argv[0], "para_server (serving %s)", peer_name);
+ handle_connect(new_fd, peer_name);
+ /* never reached*/
+out:
+ if (ret < 0)
+ PARA_CRIT_LOG("%s\n", para_strerror(-ret));
+ return 0;
+}
+
+static void init_server_command_task(int argc, char **argv)
+{
+ int ret;
+ static struct server_command_task server_command_task_struct,
+ *sct = &server_command_task_struct;
+
+ PARA_NOTICE_LOG("initializing tcp command socket\n");
+ sct->task.pre_select = command_pre_select;
+ sct->task.post_select = command_post_select;
+ sct->argc = argc;
+ sct->argv = argv;
+ ret = para_listen_simple(IPPROTO_TCP, conf.port_arg);