+ static struct signal_task signal_task_struct,
+ *st = &signal_task_struct;
+
+ st->task.pre_select = signal_pre_select;
+ st->task.post_select = signal_post_select;
+ sprintf(st->task.status, "signal task");
+
+ PARA_NOTICE_LOG("setting up signal handling\n");
+ st->fd = para_signal_init(); /* always successful */
+ para_install_sighandler(SIGINT);
+ para_install_sighandler(SIGTERM);
+ para_install_sighandler(SIGHUP);
+ para_install_sighandler(SIGCHLD);
+ para_sigaction(SIGPIPE, SIG_IGN);
+ add_close_on_fork_list(st->fd);
+ register_task(&st->task);
+}
+
+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 void 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;
+ char *info_string;
+
+ if (!FD_ISSET(sct->listen_fd, &s->rfds))
+ return;
+ ret = para_accept(sct->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();
+ /* The chunk table and the info_string are pointers located in the
+ * mmd struct that point to dynamically allocated memory that 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 these
+ * pointers are still valid in child context. As these two pointers are
+ * not used in the child anyway, we save them to local variables and
+ * free the memory via that copy in the child.
+ */
+ info_string = mmd->afd.afhi.info_string;
+ 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) {
+ close(new_fd);
+ /* parent keeps accepting connections */
+ return;
+ }
+ /* mmd might already have changed at this point */
+ free(info_string);
+ 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);
+ return handle_connect(new_fd, peer_name);
+out:
+ if (ret < 0)
+ PARA_CRIT_LOG("%s\n", para_strerror(-ret));
+}