#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>

int flag = 0;

void sig_handler(int signo)
{
	if (signo == SIGUSR1)
		flag = 1;
	else if (signo == SIGINT || signo == SIGTERM)
		flag = 2;
}

int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		fprintf(stderr, "USAGE: %s EXEC_PROCESS PORT\n"
				"Bootstrap for workflow server to restart gracefully.\n",
				argv[0]);
		exit(1);
	}

	unsigned short port = atoi(argv[2]);
	int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in sin;

	memset(&sin, 0, sizeof sin);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(listen_fd, (struct sockaddr *)&sin, sizeof sin) < 0)
	{
		close(listen_fd);
		perror("bind error");
		exit(1);
	}

	pid_t pid;
	int pipe_fd[2];
	ssize_t len;
	char buf[100];
	int status;
	int ret;

	char listen_fd_str[10] = { 0 };
	char write_fd_str[10] = { 0 };
	sprintf(listen_fd_str, "%d", listen_fd);

	signal(SIGINT, sig_handler);
	signal(SIGTERM, sig_handler);
	signal(SIGUSR1, sig_handler);

	while (flag < 2)
	{
		if (pipe(pipe_fd) == -1)
		{
			perror("open pipe error");
			exit(1);
		}

		memset(write_fd_str, 0, sizeof write_fd_str);
		sprintf(write_fd_str, "%d", pipe_fd[1]);

		pid = fork();
		if (pid < 0)
		{
			perror("fork error");
			close(pipe_fd[0]);
			close(pipe_fd[1]);
			break;
		}
		else if (pid == 0)
		{
			close(pipe_fd[0]);
			execlp(argv[1], argv[1], listen_fd_str, write_fd_str, NULL);
		}
		else
		{
			close(pipe_fd[1]);

			status = 0;
			ret = 0;
			flag = 0;
			fprintf(stderr, "Bootstrap daemon running with server pid-%d. "
					"Send SIGUSR1 to RESTART or SIGTERM to STOP.\n", pid);

			while (1)
			{
				ret = waitpid(pid, &status, WNOHANG);
				if (ret == -1 || !WIFEXITED(status) || flag != 0)
					break;

				sleep(3);
			}

			if (ret != -1 && WIFEXITED(status))
			{
				signal(SIGCHLD, SIG_IGN);

				kill(pid, SIGUSR1);
				fprintf(stderr, "Bootstrap daemon SIGUSR1 to pid-%ld %sing.\n",
						(long)pid, flag == 1 ? "restart" : "stop");

				len = read(pipe_fd[0], buf, 7);
				fprintf(stderr, "Bootstrap server served %*s.\n", (int)len, buf);
			}
			else
			{
				fprintf(stderr, "child exit. status = %d, waitpid ret = %d\n",
						WEXITSTATUS(status), ret);
				flag = 2;
			}

			close(pipe_fd[0]);
		}
	}

	close(listen_fd);
	return 0;
}

