1 /*
2  * FreeWnn is a network-extensible Kana-to-Kanji conversion system.
3  * This file is part of FreeWnn.
4  *
5  * Copyright Kyoto University Research Institute for Mathematical Sciences
6  *                 1987, 1988, 1989, 1990, 1991, 1992
7  * Copyright OMRON Corporation. 1987, 1988, 1989, 1990, 1991, 1992, 1999
8  * Copyright ASTEC, Inc. 1987, 1988, 1989, 1990, 1991, 1992
9  * Copyright FreeWnn Project 1999, 2000, 2001, 2002, 2003
10  *
11  * Maintainer:  FreeWnn Project   <freewnn@tomo.gr.jp>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 /*
29         Jserver         (Nihongo Daemon)
30 */
31 static char rcs_id[] = "$Id: de.c,v 1.36 2004/06/18 16:32:41 hiroo Exp $";
32 
33 #if defined(HAVE_CONFIG_H)
34 #  include <config.h>
35 #endif
36 #include "getopt.h"
37 
38 #include <stdio.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <signal.h>
42 #if STDC_HEADERS
43 #  include <stdlib.h>
44 #  include <string.h>
45 #else
46 #  if HAVE_MALLOC_H
47 #    include <malloc.h>
48 #  endif
49 #  if HAVE_STRINGS_H
50 #    include <strings.h>
51 #  endif
52 #endif /* STDC_HEADERS */
53 #include <sys/ioctl.h>
54 #include <sys/stat.h>
55 #if TIME_WITH_SYS_TIME
56 #  include <sys/time.h>
57 #  include <time.h>
58 #else
59 #  if HAVE_SYS_TIME_H
60 #    include <sys/time.h>
61 #  else
62 #    include <time.h>
63 #  endif /* HAVE_SYS_TIME_H */
64 #endif /* TIME_WITH_SYS_TIME */
65 #if HAVE_UNISTD_H
66 #  include <sys/types.h>
67 #  include <unistd.h>
68 #endif
69 #ifdef HAVE_FCNTL_H
70 #  include <fcntl.h>
71 #endif
72 #if HAVE_SYS_PARAM_H
73 #  include <sys/param.h>
74 #endif
75 
76 #include "getopt.h"
77 
78 #include "commonhd.h"
79 #include "wnn_config.h"
80 #include "jd_sock.h"
81 #include "demcom.h"
82 #include "wnn_os.h"
83 #define GLOBAL_VALUE_DEFINE 1
84 #include "de_header.h"
85 #undef  GLOBAL_VALUE_DEFINE
86 #include "msg.h"
87 
88 #ifdef SOLARIS
89 #ifdef SO_DONTLINGER
90 #undef SO_DONTLINGER
91 #endif
92 #endif /* SOLARIS */
93 
94 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_NONBLOCK)
95 #define USE_SETSOCKOPT 1
96 #else
97 #undef USE_SETSOCKOPT
98 #endif
99 
100 #ifndef min
101 #define min(x,y)        ( (x)<(y) ? (x) : (y) )
102 #endif
103 
104 #ifndef INET6
105 #  define OPTIONARGS  "a:Df:s:h:N:p:vu4"
106 #else
107 #  define OPTIONARGS  "a:Df:s:h:N:p:vu46"
108 #endif /* INET6 */
109 
110 /*      Accept Socket   */
111 #define MAX_ACCEPTS     256
112 
113 #define PROTO_UN	0x2
114 #define PROTO_INET	0x4
115 #define PROTO_INET6	0x8
116 #define PROTO_ALL	(PROTO_UN|PROTO_INET|PROTO_INET6)
117 static int listen_proto;
118 
119 jmp_buf client_dead;
120 
121 static int port;
122 static int serverNO;
123 
124 struct cmblk {
125 	int domain;
126 	int sd;		/* socket fd */
127 };
128 
129 /** ���饤����Ȥ��ȤΥ����åȤ��������ơ��֥� **/
130 static struct cmblk *cblk;
131 /*accept sock blocks */
132 static struct cmblk accept_blk[MAX_ACCEPTS];
133 static int bindex;
134 
135 #if defined(EAGAIN)
136 # if defined(EWOULDBLOCK)
137 # define ERRNO_CHECK(no)        ((no) == EAGAIN || (no) == EWOULDBLOCK)
138 # else /* defined(EWOULDBLOCK) */
139 # define ERRNO_CHECK(no)        ((no) == EAGAIN)
140 # endif /* defined(EWOULDBLOCK) */
141 #else /* defined(EAGAIN) */
142 # if defined(EWOULDBLOCK)
143 # define ERRNO_CHECK(no)        ((no) == EWOULDBLOCK)
144 # else /* defined(EWOULDBLOCK) */
145 # define ERRNO_CHECK(no)        (0)
146 # endif /* defined(EWOULDBLOCK) */
147 #endif /* defined(EAGAIN) */
148 
149 /*      Client Table    */
150 int clientp;            /** cblk��ͭ���ʥǡ����κǸ�����Ƥ��� **/
151 int cur_clp;            /** ���ߤΥ��饤����Ȥ��ֹ� **/
152 
153 static fd_set *all_socks;	/** �ӥåȥѥ�����
154 				    which jserver to select ���ݻ� **/
155 static fd_set *ready_socks;	/** �ǡ����Τ��Ƥ��륽���åȤ�
156 				    �ӥåȥѥ�������ݻ� **/
157 static fd_set *dummy1_socks, *dummy2_socks;
158 static int no_of_ready_socks;
159 static int nofile;              /** No. of files **/
160 struct msg_cat *wnn_msg_cat;
161 struct msg_cat *js_msg_cat;
162 
163 /* function prototypes */
164 static void daemon_main(void);
165 static void socket_disc_init(void);
166 static int sel_all(void);
167 static int  get_client(void);
168 static void new_client(void);
169 static void daemon_init(void);
170 static void daemon_fin_un(int);
171 static void daemon_fin_in(int);
172 static int  rcv_1_client(int);
173 static void snd_1_client(int, int);
174 static void socket_init_un(int *);
175 static void socket_init_in(int *);
176 static int  socket_accept(int);
177 static void xerror(char*);
178 static void get_options(int, char **);
179 static void usage(void);
180 static void print_version(void);
181 static void dmp(char*, int);
182 
183 static char cmd_name[16];
184 
185 #if defined(HAVE_LIBWRAP)
186 int allow_severity;
187 int deny_severity;
188 #  include <syslog.h>
189 #  include <tcpd.h>
190 #endif /* HAVE_LIBWRAP */
191 
192 /* No arguments are used. Only options. */
193 int
main(int argc,char * argv[])194 main(int argc, char *argv[])
195 {
196 	int tmpttyfd;
197 	pid_t pid;
198 	int fd;
199 	char *cswidth_name;
200 	extern char *get_cswidth_name ();
201 	extern void set_cswidth ();
202 
203 	char nlspath[64];
204 
205 	strcpy(cmd_name, WNN_DAEMON_NAME);
206 	strcpy(lang_dir, LANG_NAME);
207 	strcpy(nlspath, LIBDIR);
208 	strcat(nlspath, "/%L/%N");
209 	js_msg_cat = msg_open (MESSAGE_FILE, nlspath, lang_dir);
210 	wnn_msg_cat = msg_open ("libwnn.msg", nlspath, lang_dir);
211 
212 	if (wnn_msg_cat == NULL) {
213 		log_err ("cannot open message file libwnn.msg.");
214 	}
215 	if (cswidth_name = get_cswidth_name (LANG_NAME))
216 		set_cswidth (create_cswidth (cswidth_name));
217 
218 	port = -1;
219 	/* option default */
220 	option_flag = (OPT_FORK & ~OPT_VERBOSE);
221 
222 	setuid(geteuid());
223 	get_options (argc, argv);
224 	print_version();
225 	log_debug("invoked as %s.", argv[0]);
226 #if defined(HAVE_LIBWRAP)
227 	allow_severity = LOG_INFO;
228 	deny_severity = LOG_WARNING;
229 	/*  hosts_access_verbose = 2; */
230 #endif /* HAVE_LIBWRAP */
231 
232 	signal(SIGHUP, signal_hand);
233 	signal(SIGQUIT, signal_hand);
234 	signal(SIGTERM, terminate_hand);
235 	if (option_flag & OPT_FORK) {
236 		/* when -D is not specified, accept SIGINT */
237 		signal(SIGINT, signal_hand);
238 #ifdef	SIGTSTP
239 		signal(SIGTSTP, SIG_IGN);
240 #endif /* SIGTSTP */
241 	}
242 	read_default();
243 	daemon_init();
244 	env_init();
245 	if (file_init() == 0)
246 		exit (1);
247 	dic_init();
248 	if (0 == get_kaiseki_area (LENGTHCONV + 1)) {
249 		/* �Ѵ���ǽʸ���� */
250 		log_err ("get_kaiseki_area failed.");
251 		exit (1);
252 	}
253 	init_work_areas();
254 	init_jmt();
255 	read_default_files();
256 	if (option_flag & OPT_FORK) {
257 		pid = fork();
258 		if (pid == -1) {
259 			log_err ("cannot fork.");
260 			exit(1);
261 		}
262 		if (pid > 0)
263 			_exit(0);
264 		setsid();
265 		pid = fork();
266 		if (pid == -1) {
267 			log_err ("cannot fork.");
268 			exit(1);
269 		}
270 		if (pid > 0)
271 			_exit(0);
272 		chdir("/");
273 		umask(0);
274 		close(STDIN_FILENO);
275 		close(STDOUT_FILENO);
276 		if (!(option_flag & OPT_VERBOSE)) {
277 			close(STDERR_FILENO);
278 			fd = open("/dev/null", O_WRONLY);
279 			if (fd < 0) {
280 				xerror ("Cannot open /dev/null");
281 			}
282 			dup2(fd, STDERR_FILENO);
283 			close(fd);
284 		}
285 #ifdef SETPGRP_VOID
286 		setpgrp();
287 #else /* !SETPGRP_VOID */
288 # if !defined(TIOCNOTTY) && defined(SVR4)
289 #  define TIOCNOTTY     _IO('t', 113)
290 # endif /* !defined(TIOCNOTTY) && defined(SVR4) */
291 #ifndef HITACHI
292 		if ((tmpttyfd = open("/dev/tty", O_RDWR)) >= 0) {
293 			ioctl(tmpttyfd, TIOCNOTTY, 0);
294 			close(tmpttyfd);
295 		}
296 #endif /* HITACHI */
297 #endif /* SETPGRP_VOID */
298 	}
299 	daemon_main();
300 	daemon_fin();
301 	return(0);	/* NOTREACHED */
302 }
303 
304 static void
daemon_main(void)305 daemon_main (void)
306 {
307 	for (;;) {
308 		c_c = NULL;	/* Added for logging: server section */
309 		sel_all();
310 		new_client();
311 
312 		for (;;) {
313 			if (get_client () == -1)
314 				break;
315 			c_c = &client[cur_clp];
316 /*      if(rcv_1_client(cur_clp) == 0){ del_client(); continue; }       */
317 			if (setjmp(client_dead)) {
318 				del_client ();
319 				continue;
320 			}
321 			do_command(c_c);
322 		}
323 	}
324 }
325 
326 /*
327         allocs area for selecting socketts
328 */
329 static void
socket_disc_init(void)330 socket_disc_init (void)
331 {
332 	nofile = MIN(WNN_NFD, FD_SETSIZE);
333 
334 	all_socks = (fd_set *)malloc(sizeof(fd_set));
335 	ready_socks = (fd_set *)malloc(sizeof(fd_set));
336 	dummy1_socks = (fd_set *)malloc(sizeof(fd_set));
337 	dummy2_socks = (fd_set *)malloc(sizeof(fd_set));
338 	FD_ZERO(all_socks);
339 	FD_ZERO(ready_socks);
340 	FD_ZERO(dummy1_socks);
341 	FD_ZERO(dummy2_socks);
342 }
343 
344 /**     ���ƤΥ����åȤˤĤ����Ԥ�      **/
345 static int
sel_all(void)346 sel_all(void)
347 {
348 	int ns = 0;
349 	memcpy(ready_socks, all_socks, sizeof(fd_set));
350 	FD_ZERO(dummy1_socks);
351 	FD_ZERO(dummy2_socks);
352 
353 top:
354 	errno = 0;
355 	if ((no_of_ready_socks = select(nofile, ready_socks, dummy1_socks, dummy2_socks, NULL)) == -1) {
356 		if (errno == EINTR)
357 			goto top;
358 		xerror ("select error");
359 	}
360 #ifdef DEBUG
361 	log_debug ("select OK, ready_socks[0]=%02X, n-r-s=%x\n", ready_socks[0], no_of_ready_socks);
362 #endif
363 }
364 
365 /**     ready_socks���麣����ͤ���Ф����֤�(cur_clp�ˤ⥻�åȤ���)
366         ï���ʤ�����-1
367         �������塼����ϥ饦��ɥ�ӥ�        **/
368 static int
get_client(void)369 get_client (void)
370 {
371 	int i;
372 
373 	if (no_of_ready_socks == 0)
374 		return -1;                  /* no client waits service */
375 
376 	for (i = cur_clp;;)
377 	{
378 		if (no_of_ready_socks == 0)
379 			return -1;
380 		i++;
381 		if (i >= clientp)
382 			i = 0;
383 		if (FD_ISSET(cblk[i].sd, ready_socks)) {
384 			FD_CLR(cblk[i].sd, ready_socks);
385 			no_of_ready_socks--;
386 			return (cur_clp = i);
387 		}
388 	}
389 }
390 
391 /**     ���������饤����Ȥ���뤫�ݤ���Ĵ�٤�
392         �錄����cblk����Ͽ����        **/
393 static void
new_client(void)394 new_client(void)
395 {
396 	int sd = -1;
397 	int full, i;
398 	FILE *f[3];
399 	char gomi[1024];
400 #ifdef  HAVE_LIBWRAP
401 	int is_internet_socket;
402 	struct request_info tcpd_request;
403 #endif /* HAVE_LIBWRAP */
404 
405 	log_debug("new client called");
406 
407 	for (i = 0; i < bindex && !FD_ISSET(accept_blk[i].sd, ready_socks); i++)
408 		;
409 
410 	if (i == bindex)
411 		return;
412 
413 	FD_CLR(accept_blk[i].sd, ready_socks);
414 	no_of_ready_socks--;
415 	log_debug("new client: FDISSET(%d/%d) true, domain=%d",
416 		  i, bindex, accept_blk[i].domain);
417 
418 	switch (accept_blk[i].domain) {
419 #ifdef AF_UNIX
420 	case AF_UNIX:
421 		sd = socket_accept(i);
422 #ifdef  HAVE_LIBWRAP
423 		is_internet_socket = 0;
424 #endif /* HAVE_LIBWRAP */
425 		break;
426 #endif
427 #ifdef INET6
428 	case AF_INET6:
429 #endif
430 	case AF_INET:
431 		sd = socket_accept(i);
432 #ifdef  HAVE_LIBWRAP
433 		is_internet_socket = 1;
434 #endif /* HAVE_LIBWRAP */
435 		break;
436 	default:
437 		return;
438 	}
439 
440 	log_debug("new client: sd = %d (type=%d)",
441 		  sd, accept_blk[i].domain);
442 
443 	/* reserve 2 fd */
444 	for (full = i = 0; i < 2; i++) {
445 		if (NULL == (f[i] = fopen ("/dev/null", "r"))) {
446 			full = 1;
447 		}
448 	}
449 
450 	for (i = 0; i < 2; i++) {
451 		if (NULL != f[i])
452 			fclose (f[i]);
453 	}
454 
455 	if (full || sd >= nofile || clientp >= max_client) {
456 		log_err("no more client.");
457 #ifdef HAVE_RECV
458 		recv(sd, gomi, 1024, 0);
459 #else
460 		read(sd, gomi, 1024);
461 #endif
462 		shutdown(sd, 2);
463 #ifdef HAVE_CLOSESOCKET
464 		closesocket(sd);
465 #else
466 		close(sd);
467 #endif
468 		return;
469 	}
470 
471 #ifdef HAVE_LIBWRAP
472 	if (is_internet_socket) {
473 		request_init (&tcpd_request,RQ_DAEMON, WNN_DAEMON_NAME,
474 			      RQ_FILE, sd, NULL);
475 		fromhost (&tcpd_request);
476 		if (!hosts_access (&tcpd_request)) {
477 			log_err ("reject client."); /* should be log_info? */
478 			/* should we log IP address / hostname? */
479 #ifdef HAVE_RECV
480 			recv(sd, gomi, 1024, 0);
481 #else
482 			read(sd, gomi, 1024);
483 #endif
484 			shutdown(sd, 2);
485 #ifdef HAVE_CLOSESOCKET
486 			closesocket(sd);
487 #else
488 			close(sd);
489 #endif
490 			return;
491 		}
492 	}
493 #endif /*  HAVE_LIBWRAP */
494 
495 	cblk[clientp].sd = sd;
496 	FD_SET(sd, all_socks);
497 	for (i = 0; i < WNN_MAX_ENV_OF_A_CLIENT; i++) {
498 		(client[clientp].env)[i] = -1;
499 	}
500 	clientp++;
501 }
502 
503 /**     ���饤����Ȥ�cblk����������  **/
504 /* delete Client (please call from JS_CLOSE) */
505 void
del_client(void)506 del_client (void)
507 {
508 	disconnect_all_env_of_client ();
509 	FD_CLR(cblk[cur_clp].sd, all_socks);
510 #ifdef HAVE_CLOSESOCKET
511 	closesocket(cblk[cur_clp].sd);
512 #else
513 	close(cblk[cur_clp].sd);
514 #endif
515   /* logging here because c_c (used in log_debug) will be broken after
516      following section */
517 	log_debug("Delete Client: cur_clp = %d\n", cur_clp);
518 	cblk[cur_clp] = cblk[clientp - 1];
519 	client[cur_clp] = client[clientp - 1];
520 	/* Clear host/user name with zero - needed for logging */
521 
522 	/* Should we use bzero()? */
523 	client[clientp - 1].user_name[0] = '\0';
524 
525 	client[clientp - 1].host_name[0] = '\0';
526 	clientp--;
527 }
528 
529 /**     �����Ф��˥���饤������      **/
530 static void
daemon_init(void)531 daemon_init(void)               /* initialize Daemon */
532 {
533 	/*
534 	  signal (SIGHUP, SIG_IGN);
535 	  signal (SIGINT, SIG_IGN);
536 	  signal (SIGQUIT, SIG_IGN);
537 	*/
538 
539 	if ((cblk = (struct cmblk *)malloc(max_client * sizeof(struct cmblk))) == NULL) {
540 		xerror ("daemon_init: ");
541 	}
542 
543 	if ((client = (CLIENT *)malloc(max_client * sizeof (CLIENT))) == NULL) {
544 		xerror ("daemon_init: ");
545 	}
546 
547 	SDRAND(time(NULL));
548 	clientp = 0;                  /* V3.0 */
549 	cur_clp = 0;                  /* V3.0 */
550 	socket_disc_init();
551 
552 #ifdef  AF_UNIX
553 	if (listen_proto & PROTO_UN)
554 		socket_init_un(&bindex);
555 #endif
556 	if (listen_proto & (PROTO_INET|PROTO_INET6))
557 		socket_init_in(&bindex);
558 }
559 
560 /**     �����Ф����  **/
561 #ifdef AF_UNIX
562 static void
daemon_fin_un(int sock_d_un)563 daemon_fin_un(int sock_d_un)
564 {
565 	int trueFlag = 1;
566 	struct sockaddr_un addr_un;
567 	socklen_t addrlen;
568 
569 #ifndef SOLARIS
570 #if defined(FIONBIO)
571 	ioctl (sock_d_un, FIONBIO, &trueFlag);
572 #endif
573 #else /* !SOLARIS */
574 	fcntl (sock_d_un, F_SETFL, F_UNLCK);
575 #endif /* !SOLARIS */
576 	for (;;) {
577 		addrlen = sizeof (addr_un);
578 		if (accept(sock_d_un,
579 			   (struct sockaddr *)&addr_un,
580 			   &addrlen) < 0)
581 			break;
582 		/* EWOULDBLOCK EXPECTED, but we don't check */
583         }
584 	shutdown (sock_d_un, 2);
585 	close (sock_d_un);
586 }
587 #endif /* AF_UNIX */
588 
589 static void
daemon_fin_in(int sock_d_in)590 daemon_fin_in(int sock_d_in)
591 {
592 	int trueFlag = 1;
593 	struct sockaddr_in addr_in;
594 	socklen_t addrlen;
595 #ifdef USE_SETSOCKOPT
596 	int on = ~0;
597 #endif
598 
599 #ifndef SOLARIS
600 #ifdef USE_SETSOCKOPT
601 	setsockopt(sock_d_in, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int));
602 #else
603 #if defined(FIONBIO)
604 	ioctl(sock_d_in, FIONBIO, &trueFlag);
605 #endif
606 #endif /* USE_SETSOCKOPT */
607 #else /* !SOLARIS */
608 	fcntl(sock_d_in, F_SETFL, F_UNLCK);
609 #endif /* !SOLARIS */
610 	for (;;) {
611 		addrlen = sizeof(addr_in);
612 		if (accept(sock_d_in,
613 			   (struct sockaddr *)&addr_in,
614 			   &addrlen) < 0)
615 			break;
616 		/* EWOULDBLOCK EXPECTED, but we don't check */
617 	}
618 	shutdown (sock_d_in, 2);
619 #ifdef HAVE_CLOSESOCKET
620 	closesocket (sock_d_in);
621 #else
622 	close (sock_d_in);
623 #endif
624 }
625 
626 void
daemon_fin(void)627 daemon_fin (void)
628 {
629 	int i;
630 	int fd;
631 
632 	for (i = 0; i < bindex; i++) {
633 		if (FD_ISSET(accept_blk[i].sd, all_socks)) {
634 			switch (accept_blk[i].domain) {
635 #ifdef  AF_UNIX
636 			case AF_UNIX:
637 				if (listen_proto & PROTO_UN)
638 					daemon_fin_un(accept_blk[i].sd);
639 				break;
640 #endif
641 			case AF_INET:
642 				if (listen_proto & PROTO_INET)
643 					daemon_fin_in(accept_blk[i].sd);
644 				break;
645 #ifdef INET6
646 			case AF_INET6:
647 				if (listen_proto & PROTO_INET6)
648 					daemon_fin_in(accept_blk[i].sd);
649 				break;
650 #endif
651 			default:
652 				break;
653 			}
654 		}
655 	}
656 
657 	for (fd = nofile - 1; fd >= 0; fd--) {
658 		if (FD_ISSET(fd, all_socks)) {
659 			shutdown (fd, 2);
660 #ifdef HAVE_CLOSESOCKET
661 			closesocket (fd);
662 #else
663 			close (fd);
664 #endif
665 		}
666 	}
667 }
668 
669 static unsigned char snd_buf[S_BUF_SIZ];         /** �����Хåե� **/
670 static unsigned char *sp = snd_buf;
671 
672 static unsigned char rcv_buf[R_BUF_SIZ];         /** �����Хåե� **/
673 static unsigned char *rbp = rcv_buf;
674 static unsigned char *rp = rcv_buf;
675 
676 char *
gets_cur(char * buffer,size_t buffer_size)677 gets_cur(char *buffer, size_t buffer_size)
678 {
679 	char *b;
680 
681 	if (!buffer || !buffer_size)
682 		return NULL;
683 
684 	b = buffer;
685 
686 	while (--buffer_size && (*b = getc_cur()) != '\0')
687 		b++;
688 
689 	if (!buffer_size) {
690 		*b = '\0';
691 		while (getc_cur() != '\0')
692 			;
693 	}
694 
695 	return buffer;
696 }
697 
698 /**     **/
699 w_char *
getws_cur(w_char * buffer,size_t buffer_size)700 getws_cur(w_char *buffer, size_t buffer_size)
701 {
702 	w_char *b;
703 
704 	if (!buffer || !buffer_size)
705 		return NULL;
706 
707 	b = buffer;
708 
709 	while (--buffer_size && (*b = get2_cur ()) != 0)
710 		b++;
711 
712 	if (!buffer_size) {
713 		*b = 0;
714 		while (getc_cur () != 0)
715 			;
716 	}
717 	return buffer;
718 }
719 
720 /**     �����ȡ����饤����Ȥ���2�Х��ȼ��   **/
721 int
get2_cur(void)722 get2_cur (void)
723 {
724 	int h;
725 	h  = getc_cur () << 8;
726 	h |= getc_cur ();
727 	return h;
728 }
729 
730 /**     �����ȡ����饤����Ȥ���4�Х��ȼ��   **/
731 int
get4_cur(void)732 get4_cur (void)
733 {
734 	int h;
735 	h  = getc_cur() << (8*3);
736 	h |= getc_cur() << (8*2);
737 	h |= getc_cur() << (8*1);
738 	h |= getc_cur() << (8*0);
739 	return h;
740 }
741 
742 /**     �����ȡ����饤����Ȥ���1�Х��ȼ��   **/
743 int
getc_cur(void)744 getc_cur(void)
745 {
746 #if DEBUG_IO
747 	fprintf(stderr, "getc_cur: Enter\n");
748 #endif
749 	if (rp == rbp) {
750 		rcv_1_client(cur_clp);
751 	}
752 #if DEBUG_IO
753 	fprintf(stderr, "getc_cur: [%02x]\n", *rbp & 0xff);
754 #endif
755 	return *(rbp++) & 0xff;
756 }
757 
758 /**     ���饤����Ȥ���1�ѥ��åȼ��   **/
759 static int
rcv_1_client(int clp)760 rcv_1_client(int clp)		/* clp=���饤������ֹ� */
761 {
762 	int n = 0;
763 
764 	if (rbp == rp) {
765 		rbp = rp = &rcv_buf[0];
766 	}
767 
768 	while (rbp == rp) {
769 		errno = 0;
770 #ifdef HAVE_RECV
771 		n = recv(cblk[clp].sd, rcv_buf, sizeof(rcv_buf), 0);
772 #else
773 		n = read(cblk[clp].sd, rcv_buf, sizeof(rcv_buf));
774 #endif
775 		if (n <= 0) {
776 			if (ERRNO_CHECK (errno)) {
777 				continue;
778 			} else if (n == 0) {
779 				/* client dead */
780 				longjmp(client_dead, 666);
781 			} else  {
782 				/* n == -1 */
783 				if (errno != EINTR)
784 					longjmp (client_dead, 666);
785 				continue;
786 			}
787 		}
788 		rp += n;
789 		log_debug ("rcv: clp=%d, sd=%d, n=%d\n", clp, cblk[clp].sd, n);
790 #if DEBUG_IO
791 		dmp(rbp, rp - rbp);
792 #endif
793 	}
794 
795 	return n;
796 }
797 
798 /**     ���饤����Ȥ�1�ѥ��å�����     **/
799 static void
snd_1_client(int clp,int dummy)800 snd_1_client(int clp, int dummy)
801 {
802 	unsigned char *bp = snd_buf;
803 	int n;
804 	size_t total = sp - bp;
805 
806 #if DEBUG_IO
807 	fprintf(stderr, "snd: clp=%d, sd=%d\n", clp, cblk[clp].sd);
808 	dmp(snd_buf, sp - bp);
809 #endif
810 
811 	while (0 < sp - bp && sp <= snd_buf + sizeof(snd_buf)) {
812 		errno =0;
813 #ifdef HAVE_SEND
814 		n = send(cblk[clp].sd, bp, sp - bp, 0);
815 #else
816 		n = write(cblk[clp].sd, bp, sp - bp);
817 #endif
818 		if (n < 0) {
819 			if (ERRNO_CHECK (errno) || errno == EINTR) {
820 				continue;
821 			} else {
822 				/* client dead */
823 				longjmp (client_dead, 666);
824 			}
825 		}
826 		bp += n;
827 	}
828 	sp = snd_buf;
829 }
830 
831 void
puts_cur(char * p)832 puts_cur(char *p)
833 {
834 	int c;
835 	while(c = *p++)
836 		putc_cur(c);
837 	putc_cur(0x00);
838 }
839 
840 void
puts_n_cur(char * p,int n)841 puts_n_cur(char *p, int n)
842 {
843 	int c;
844 	while ((c = *p++) && --n >= 0)
845 		putc_cur(c);
846 	putc_cur(0x00);
847 }
848 
849 void
putws_cur(w_char * p)850 putws_cur(w_char *p)
851 {
852 	int c;
853 	while (c = *p++)
854 		put2_cur(c);
855 	put2_cur(0x0000);
856 }
857 
858 void
putnws_cur(w_char * p,int n)859 putnws_cur(w_char *p, int n)
860 {
861 	unsigned int c;
862 	for (; n > 0; n--) {
863 		if ((c = *p++) == 0)
864 			break;
865 		put2_cur(c);
866 	}
867 	put2_cur(0x0000);
868 }
869 
870 void
put2_cur(int c)871 put2_cur(int c)
872 {
873 	putc_cur(c >> (8 * 1));
874 	putc_cur(c);
875 }
876 
877 void
put4_cur(int c)878 put4_cur(int c)
879 {
880 	putc_cur(c >> (8 * 3));
881 	putc_cur(c >> (8 * 2));
882 	putc_cur(c >> (8 * 1));
883 	putc_cur(c);
884 }
885 
886 void
putc_cur(int c)887 putc_cur(int c)
888 {
889 #if DEBUG_IO
890 	fprintf(stderr, "putc_cur: Enter\n");
891 #endif
892 	if (snd_buf + sizeof(snd_buf) <= sp)
893 		putc_purge();
894 
895 #if DEBUG_IO
896 	fprintf(stderr, "putc_cur: [%02x]\n", c & 0xff);
897 #endif
898 	*(sp++) = c & 0xff;
899 }
900 
901 /* flush send buffer */
902 void
putc_purge(void)903 putc_purge(void)
904 {
905 	if (snd_buf < sp) {
906 		snd_1_client(cur_clp, 0);
907 	}
908 }
909 
910 /* initialize sockets */
911 #ifdef  AF_UNIX
912 #if !defined(SUN_LEN)
913 # define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
914 #endif
915 
916 static void
socket_init_un(int * index)917 socket_init_un(int *index)
918 {
919 	struct sockaddr_un saddr_un;
920 	int sock_d_un;
921 
922 	saddr_un.sun_family = AF_UNIX;
923 	strncpy(saddr_un.sun_path, sockname, sizeof(saddr_un.sun_path) - 1);
924 	saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
925 
926 	unlink(saddr_un.sun_path);
927 
928 	if ((sock_d_un = socket(saddr_un.sun_family, SOCK_STREAM, 0)) == ERROR)
929 		xerror("could not create unix domain socket");
930 
931 	if (bind(sock_d_un,
932 		 (struct sockaddr *)&saddr_un,
933 		 SUN_LEN(&saddr_un)) == ERROR) {
934 		shutdown (sock_d_un, 2);
935 		xerror("could not bind unix domain socket");
936         }
937 
938 	if (listen(sock_d_un, 5) == ERROR) {
939 		shutdown (sock_d_un, 2);
940 		xerror("could not listen unix domain socket");
941         }
942 
943 	chmod(sockname, 0777);
944 	signal(SIGPIPE, SIG_IGN);
945 	log_debug("sock_d_un = %d (bindex=%d)", sock_d_un, *index);
946 	accept_blk[(*index)].sd = sock_d_un;
947 	accept_blk[(*index)].domain = saddr_un.sun_family;
948 	(*index)++;
949 	FD_SET (sock_d_un, all_socks);
950 }
951 #endif /* AF_UNIX */
952 
953 /*      Inet V3.0 */
954 static void
socket_init_in(int * index)955 socket_init_in(int *index)
956 {
957 	int i;
958 #ifndef SOLARIS
959 	int on = 1;
960 #else /* SOLARIS */
961 	int on = 0;
962 #endif /* SOLARIS */
963 
964 	struct servent *sp;
965 #if !defined(SO_DONTLINGER) && defined(SO_LINGER)
966 	struct linger linger;
967 #endif
968 	struct addrinfo hints, *res, *res0;
969 	struct sockaddr sa;
970 	int error;
971 	char hbuf[NI_MAXHOST];
972 	char sbuf[NI_MAXSERV];
973 	int sock_d_in;
974 
975 	memset(&sa, 0, sizeof(struct sockaddr));
976 	if (port < 0) {
977 		strncpy(sbuf, SERVERNAME, sizeof(sbuf) - 1);
978 		sbuf[sizeof(sbuf) - 1] = '\0';
979 		error = getnameinfo(&sa,
980 				    sa.sa_len,
981 				    NULL,
982 				    0,
983 				    sbuf,
984 				    sizeof(sbuf),
985 				    NI_NUMERICSERV);
986 		if (error)
987 			sprintf(sbuf, "%d", WNN_PORT_IN);
988 	} else {
989 		sprintf(sbuf, "%d", port);
990 	}
991 
992 	port += serverNO;
993 
994 	memset(&hints, 0, sizeof(hints));
995 	if (listen_proto & PROTO_INET
996 	    || listen_proto & PROTO_INET6)
997 		hints.ai_family = PF_UNSPEC;
998 	hints.ai_socktype = SOCK_STREAM;
999 	hints.ai_flags = AI_PASSIVE;
1000 
1001 	for (i = 0; i < MAXLISTENADDR && listenaddr[i][0] != '\0'; i++) {
1002 		log_debug("getaddrinfo: try %s",listenaddr[i]);
1003 
1004 		if (error = getaddrinfo(listenaddr[i], sbuf, &hints, &res0))
1005 			xerror((char *)gai_strerror(error));
1006 
1007 		for (res = res0; res; res = res->ai_next) {
1008 			log_debug("socket: try %s : %s (type=%d)",
1009 				  listenaddr[i], sbuf, res->ai_family);
1010 
1011 			switch (res->ai_family) {
1012 			case AF_INET:
1013 				if (!(listen_proto & PROTO_INET)) {
1014 					log_debug("socket: ignore %s\n", listenaddr[i]);
1015 					continue;
1016 				}
1017 				sock_d_in = socket(res->ai_family,
1018 						   res->ai_socktype,
1019 						   res->ai_protocol);
1020 				if (sock_d_in == -1)
1021 					xerror("could not create inet socket");
1022 				break;
1023 #ifdef INET6
1024 			case AF_INET6:
1025 				if (!(listen_proto & PROTO_INET6)) {
1026 					log_debug("socket: ignore %s\n", listenaddr[i]);
1027 					continue;
1028 				}
1029 				sock_d_in = socket(res->ai_family,
1030 						   res->ai_socktype,
1031 						   res->ai_protocol);
1032 				if (sock_d_in == -1)
1033 					xerror("could not create inet6 socket");
1034 #ifdef IPV6_V6ONLY
1035 				setsockopt(sock_d_in, IPPROTO_IPV6, IPV6_V6ONLY, NULL, 0);
1036 #endif
1037 #endif /* INET6 */
1038 			default:
1039 				continue;
1040 			}
1041 			setsockopt (sock_d_in, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (int));
1042 #ifdef SO_DONTLINGER
1043 			setsockopt (sock_d_in, SOL_SOCKET, SO_DONTLINGER, (char *) 0, 0);
1044 #else
1045 # ifdef SO_LINGER
1046 			linger.l_onoff = 0;
1047 			linger.l_linger = 0;
1048 			setsockopt(sock_d_in, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof linger);
1049 # endif /* SO_LINGER */
1050 #endif /* SO_DONTLINGER */
1051 
1052 			if (bind(sock_d_in, res->ai_addr, res->ai_addrlen) == ERROR) {
1053 				shutdown (sock_d_in, 2);
1054 				xerror("could not bind inet/inet6 socket");
1055 			}
1056 
1057 			if (listen(sock_d_in, 5) == ERROR) {
1058 				shutdown (sock_d_in, 2);
1059 				xerror("could not listen inet/inet6 socket");
1060 			}
1061 
1062 			log_debug("sock_d_in = %d (bindex=%d)",
1063 				  sock_d_in, *index);
1064 			FD_SET(sock_d_in, all_socks);
1065 			accept_blk[(*index)].sd = sock_d_in;
1066 			accept_blk[(*index)].domain = res->ai_family;
1067 			(*index)++;
1068 		}
1069 	}
1070 	freeaddrinfo(res0);
1071 }
1072 
1073 /**     accept new client socket        **/
1074 static int
socket_accept(int index)1075 socket_accept(int index)
1076 {
1077 	return accept(accept_blk[index].sd, NULL, NULL);
1078 }
1079 
1080 static void
xerror(char * s)1081 xerror(char *s)
1082 {
1083 	log_err ("%s (%s).", s, strerror(errno));
1084 	exit (1);
1085 }
1086 
1087 static void
dmp(char * p,int n)1088 dmp(char *p, int n)
1089 {
1090 	int i, j;
1091 
1092 	for (i = 0; i < n; i += 16) {
1093 		for (j = 0; j < 16; j++) {
1094 			fprintf (stderr, "%02x ", p[i + j] & 0xFF);
1095 		}
1096 		fprintf (stderr, "n=%d\n", n);
1097 	}
1098 }
1099 
1100 static void
get_options(int argc,char ** argv)1101 get_options(int argc, char **argv)
1102 {
1103 	int c;
1104 	int digit_optind = 0;
1105 	int lindex = 0;
1106 
1107 	strcpy (jserverrcfile, LIBDIR);       /* usr/local/lib/wnn */
1108 	strcat (jserverrcfile, SERVER_INIT_FILE);     /* ja_JP/jserverrc */
1109 
1110 	while (1)
1111 	{
1112 		int this_option_optind = optind ? optind : 1;
1113 		int option_index = 0;
1114 		static struct option long_options[] =
1115 			{
1116 				{"baseport",	1, NULL, 'p'},
1117 				{"inet",	0, NULL, '4'},
1118 				{"inet6",	0, NULL, '6'},
1119 				{"jserverrc",	1, NULL, 'f'},
1120 				{"listenaddr",	1, NULL, 'a'},
1121 				{"unix",	0, NULL, 'u'},
1122 				{"version",	0, NULL, 'v'},
1123 				{0, 0, 0, 0}
1124 			};
1125 
1126 		c = getopt_long (argc, argv, OPTIONARGS,
1127 				 long_options, &option_index);
1128 		if (c == -1)
1129 			break;
1130 
1131 		switch (c)
1132 		{
1133 		case 'D': /* do not detach, not a daemon */
1134 			option_flag &= ~OPT_FORK;
1135 			break;
1136 
1137 		case 'f': /* --jserverrc FILENAME */
1138 			strncpy(jserverrcfile, optarg, sizeof(jserverrcfile) - 1);
1139 			jserverrcfile[sizeof(jserverrcfile) - 1] = '\0';
1140 			break;
1141 
1142 		case 'a': /* --listenaddr ADDR */
1143 			strncpy(listenaddr[lindex], optarg, NI_MAXHOST - 1);
1144 			listenaddr[lindex][NI_MAXHOST - 1] = '\0';
1145 			lindex++;
1146 			break;
1147 
1148 		case 's':
1149 			/* should nuke noisy someday */
1150 			noisy = 1; option_flag |= OPT_VERBOSE;
1151 			if (strcmp ("-", optarg) != 0)
1152 			{
1153 				/** maybe FILE wnnerr = stderr; or wnnerr = open(optarg...) is better? or freopen is normal method? */
1154 				/** take a look at daemon(3) */
1155 				if (freopen (optarg, "a", stderr) == NULL)
1156 				{
1157 					/** fprintf to stderr? */
1158 					printf ("Error in opening scriptfile %s.\n", optarg);
1159 					exit (1);
1160 				}
1161 			}
1162 			log_debug ("script started");
1163 			break;
1164 
1165 		case 'h':
1166 			/* var hinsi_file_name polluted */
1167 			hinsi_file_name = optarg;
1168 			break;
1169 
1170 		case 'N':
1171 			serverNO = atoi (optarg);
1172 			/* error handling needed */
1173 			break;
1174 
1175 		case 'p':
1176 			port = atoi (optarg);
1177 			/* error handling needed */
1178 			break;
1179 
1180 		case 'v':
1181 			print_version();
1182 			usage();
1183 			break;
1184 
1185 		case 'u':
1186 			listen_proto |= PROTO_UN;
1187 			break;
1188 
1189 		case '4':
1190 			listen_proto |= PROTO_INET;
1191 			break;
1192 
1193 #ifdef INET6
1194 		case '6':
1195 			listen_proto |= PROTO_INET6;
1196 			break;
1197 #endif /* INET6 */
1198 		default:
1199 			print_version();
1200 			usage();
1201 			break;
1202 		}
1203 	}
1204 	if (!listen_proto) {
1205 		listen_proto = PROTO_ALL;
1206 	}
1207 }
1208 
1209 
1210 void
js_who(void)1211 js_who (void)
1212 {
1213 	int i, j;
1214 
1215 	put4_cur (clientp);
1216 	for (i = 0; i < clientp; i++)
1217 	{
1218 		put4_cur (cblk[i].sd);
1219 		puts_cur (client[i].user_name);
1220 		puts_cur (client[i].host_name);
1221 		for (j = 0; j < WNN_MAX_ENV_OF_A_CLIENT; j++)
1222 		{
1223 			put4_cur ((client[i].env)[j]);
1224 		}
1225 
1226 	}
1227 	putc_purge();
1228 }
1229 
1230 void
js_kill(void)1231 js_kill (void)
1232 {
1233   if (clientp == 1)
1234     {
1235 	    put4_cur(0x00000000);
1236       putc_purge();
1237       terminate_hand ();
1238     }
1239   else
1240     {
1241       put4_cur (clientp - 1);
1242       putc_purge();
1243     }
1244 }
1245 
1246 void
usage(void)1247 usage (void)
1248 {
1249   fprintf(stderr,
1250 #ifdef INET6
1251 	  "usage: %s [-Du46][-f <init_file> -a <listenaddr> -s <log_file(\"-\" for stderr)> -h <pos_file> -N <serverNO> -p <port_base>]\n",
1252 #else
1253 	  "usage: %s [-Du4][-f <init_file> -a <listenaddr> -s <log_file(\"-\" for stderr)> -h <pos_file> -N <serverNO> -p <port_base>]\n",
1254 #endif
1255 	  cmd_name);
1256   fprintf(stderr,
1257 	  "       %s -v\n",
1258 	  cmd_name);
1259   exit (1);
1260 }
1261 
1262 void
print_version(void)1263 print_version (void)
1264 {
1265 #if  defined(CHINESE)
1266   printf ("%s (%s) Chinese Multi Client Server\n", cmd_name, SER_VERSION);
1267 #elif  defined(KOREAN)
1268   printf ("%s (%s) Korean Multi Client Server\n", cmd_name, SER_VERSION);
1269 #else
1270   printf ("%s (%s) Nihongo Multi Client Server\n", cmd_name, SER_VERSION);
1271 #endif /* CHINESE */
1272 }
1273