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