Package-Name: wnn7
Dummy-Package: yes
# Downloadable stuff at http://www.omronsoft.co.jp/SP/download/pcunix/wnn7/wnn7updates.html
dpkey7multi-c: <<EOT
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
//FIXME: gcc 3.2.1 bug (#include <limits.h> followed by <linux/limits.h>
//       ignores linux/limits.h)
//#include <sys/param.h>
#include <linux/limits.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define NUM_SERVERS	10
#define REAL_PORT	2024
#define START_PORT	2030
#define SERVER_FILENAME	"/pkg/wnn7/sbin/dpkeyserv%d"
// dpkeyserv binary's port number is at VA 0x8048612 in network byte order

static int child_pid[NUM_SERVERS];
static int in_use[NUM_SERVERS];
static int id[NUM_SERVERS];

/*************************************************************************/

static void die(int syserr, const char *fmt,...)
{
    va_list args;
    int i;

    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    if (syserr)
	perror("");
    else
	fprintf(stderr, "\n");
    signal(SIGTERM, SIG_IGN);
    kill(-getpid(), SIGTERM);
    exit(1);
}

/*************************************************************************/

static void exec_server(int i)
{
    char buf[512];
    int j;
    for (j = 0; j < OPEN_MAX; j++)
	close(j);
    snprintf(buf, sizeof(buf), SERVER_FILENAME, i);
    setenv("LD_LIBRARY_PATH", "/pkg/wnn7/glibc-2.2.5", 1); /*FIXME*/
    execl(buf, buf, NULL);
    fprintf(stderr, "exec(%s): %s\n", buf, strerror(errno));
    exit(127);
}

/*************************************************************************/

static void sighandler(int signum)
{
    die(0, "%s", strsignal(signum));
}

/*************************************************************************/

static void child_handler(int sig_unused)
{
    int i, j, status;

    while ((i = waitpid(-1, &status, WNOHANG)) > 0) {
//printf("got child: %d\n",i);
	if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
	    continue;
	for (j = 0; j < NUM_SERVERS; j++) {
	    if (child_pid[j] == i) {
		in_use[j] = 0;
		child_pid[j] = fork();
		if (child_pid[j] == 0)
		    exec_server(j);
		else if (child_pid[j] == -1)
		    die(1, "fork()");
//printf("  restarting %d: %d -> %d\n",j,i,child_pid[j]);
		break;
	    }
	}
    }
}

/*************************************************************************/

int main(int ac, char **av)
{
    char buf[512];
    struct sockaddr_in sin_main, sin_child[NUM_SERVERS];
    int main_fd, child_fd[NUM_SERVERS];
    int i;

    for (i = 1; i <= 32; i++)
	signal(i, sighandler);
    signal(SIGCHLD, child_handler);
    signal(SIGHUP, SIG_IGN);
    signal(SIGTSTP, SIG_IGN);
    signal(SIGCONT, SIG_IGN);
    signal(SIGWINCH, SIG_IGN);

    if ((main_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
	die(1, "socket(main_fd)");
    memset(&sin_main, 0, sizeof(sin_main));
    sin_main.sin_family = AF_INET;
    sin_main.sin_port = htons(REAL_PORT);
    if (bind(main_fd, (struct sockaddr *)&sin_main, sizeof(sin_main)) < 0)
	die(1, "bind(main_fd)");

    for (i = 0; i < NUM_SERVERS; i++) {
	if ((child_fd[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
	    die(1, "socket(child_fd[%d])", i);
	memset(&sin_child[i], 0, sizeof(sin_child[i]));
	sin_child[i].sin_family = AF_INET;
	if (bind(child_fd[i], (struct sockaddr *)&sin_child[i], sizeof(sin_child[i])) < 0)
	    die(1, "bind(child_fd[%d])", i);
	child_pid[i] = fork();
	if (child_pid[i] == 0)
	    exec_server(i);
	else if (child_pid[i] == -1)
	    die(1, "fork()");
    }

    for (;;) {
	struct sockaddr_in sin_from;
	int len = sizeof(sin_from);
	fd_set fds;
	int this_id;

	FD_ZERO(&fds);
	FD_SET(main_fd, &fds);
	for (i = 0; i < NUM_SERVERS; i++)
	    FD_SET(child_fd[i], &fds);
	i = select(OPEN_MAX, &fds, NULL, NULL, NULL);
	if (i <= 0)
	    continue;
	if (FD_ISSET(main_fd, &fds)) {
	    len = recvfrom(main_fd, buf, sizeof(buf), 0,
			   (struct sockaddr *)&sin_from,
			   (unsigned int *)&len);
//printf("recv:main:%d\n",len);
/* $B%Q%1%C%H7A<0(B
 * 0x01  int8   $B%3%^%s%I(B
 *              $B#1!'%;%C%7%g%s3+;O(B
 *              $B#4!'%;%C%7%g%s=*N;(B
 * 0x28  int32  $B%;%C%7%g%s#I#D(B
 */
	    if (len < 2)
		continue;
	    this_id = (len>=44 ? *((int *)(buf+40)) : 0);
	    if (buf[1] == 4) {
		for (i = 0; i < NUM_SERVERS; i++) {
/* port test was commented out, but this causes more failures? */
		    if (in_use[i] == sin_from.sin_port && id[i] == this_id) {
			in_use[i] = 0;
			break;
		    }
		}
	    } else if (buf[1] == 1) {
		for (i = 0; i < NUM_SERVERS; i++) {
		    if (in_use[i] == 0) {
			in_use[i] = sin_from.sin_port;
			id[i] = this_id;
			break;
		    }
		}
	    } else {
		for (i = 0; i < NUM_SERVERS; i++) {
/* as above re port test */
		    if (in_use[i] == sin_from.sin_port && id[i] == this_id)
			break;
		}
	    }
	    if (i < NUM_SERVERS) {
		sin_from.sin_port = htons(START_PORT+i);
		sendto(child_fd[i], buf, len, 0,
		       (struct sockaddr *)&sin_from, sizeof(sin_from));
//printf("send:cld%d:%d\n",i,len);
	    }
	}
	for (i = 0; i < NUM_SERVERS; i++) {
	    if (FD_ISSET(child_fd[i], &fds)) {
		len = recv(child_fd[i], buf, sizeof(buf), 0);
//printf("recv:cld%d:%d\n",i,len);
		if (len > 0) {
		    sin_from.sin_family = AF_INET;
		    memcpy(&sin_from.sin_addr, "\x7F\x00\x00\x01", 4);
		    sin_from.sin_port = in_use[i];
		    sendto(main_fd, buf, len, 0,
			   (struct sockaddr *)&sin_from, sizeof(sin_from));
//printf("send:main:%d\n",len);
		}
	    }
	}
    }

}

/*************************************************************************/
EOT

-/etc/dpkey/
-/etc/wnn7/
-/var/lib/wnn7/dic/usr/
/etc/dpkey/
/etc/wnn7/
/etc/rc.d/init.d/dpkey7
/etc/rc.d/init.d/dpkey7-multi
/etc/rc.d/init.d/wnn7
/etc/rc.d/rc?.d/???dpkey7
/etc/rc.d/rc?.d/???dpkey7-multi
/etc/rc.d/rc?.d/???wnn7
/pkg/wnn7/
/usr/bin/wnnatod
/usr/bin/wnnbushu
/usr/bin/wnndictutil
/usr/bin/wnndtoa
/usr/bin/wnnenvutil
/usr/bin/wnnstat
/usr/bin/wnnsysenv_client
/usr/bin/xwnmo
/usr/lib/wnn7
/usr/share/wnn7
/var/lib/dpkey/
/var/lib/wnn7/
