1 /*  esecannaserver --- pseudo canna server that wraps another IME.
2  *  Copyright (C) 1999-2000 Yasuhiro Take
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <sys/un.h>
30 #include <netdb.h>
31 #include <errno.h>
32 
33 #include "def.h"
34 #include "misc.h"
35 
36 static struct sockaddr_un unaddr;
37 static struct sockaddr_in inaddr;
38 static int canna_unixfd, canna_inetfd;
39 
40 extern client_t client[];
41 
42 /*
43  * canna_socket_open_unix : unix �ɥᥤ��Υ����åȤ���������
44  *                        : �ե�����ǥ�������ץ����֤�
45  */
46 
canna_socket_open_unix()47 static int canna_socket_open_unix()
48 {
49   int old_umask;
50   int fd;
51 
52   old_umask = umask(0);
53 
54   mkdir(CANNA_UNIX_DOMAIN_DIR, 0777);
55 
56   if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
57     m_msg("Cannot open unix domain socket.\n");
58     return -1;
59   }
60 
61   unaddr.sun_family = AF_UNIX;
62   strcpy(unaddr.sun_path, CANNA_UNIX_DOMAIN_PATH);
63 
64   if (bind(fd, (struct sockaddr *)(&unaddr), sizeof unaddr)) {
65     close(fd);
66     m_msg("Cannot bind.\n");
67     m_msg("Another cannaserver detected.\n");
68     m_msg("If you're sure cannaserver is not running,\n");
69     m_msg("remove /tmp/.iroha_unix/IROHA.\n");
70     return -1;
71   }
72 
73   if (listen(fd, 5)) {
74     close(fd);
75     m_msg("Cannot listen.\n");
76     return -1;
77   }
78 
79   umask(old_umask);
80 
81   return fd;
82 }
83 
84 /*
85  * canna_socket_open_inet : inet �ɥᥤ��Υ����åȤ���������
86  *                        : �ե�����ǥ�������ץ����֤�
87  */
88 
canna_socket_open_inet()89 static int canna_socket_open_inet()
90 {
91   struct servent *s;
92   int one = 1, fd, i;
93 
94   if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
95     m_msg("Cannot open inet domain socket.\n");
96     return -1;
97   }
98 
99 #ifdef SO_REUSEADDR
100   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&one),
101 	     sizeof (int));
102 #endif
103 
104   s = getservbyname(CANNA_SERVICE_NAME, "tcp");
105 
106   memset((char *)&inaddr, 0, sizeof inaddr);
107   inaddr.sin_family = AF_INET;
108   inaddr.sin_port = s ? s->s_port : htons(CANNA_DEFAULT_PORT);
109   inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
110 
111   if ((i = bind(fd, (struct sockaddr *)(&inaddr), sizeof inaddr)) != 0) {
112     m_msg("Bind refused.\n");
113     return -1;
114   }
115 
116   if (listen (fd, 5)) {
117     close(fd);
118     m_msg("Cannot listen.\n");
119     return -1;
120   }
121 
122   return fd;
123 }
124 
125 /*
126  * canna_socket_open : unix, inet �ɥᥤ��Υ����åȤ��������롣
127  */
128 
canna_socket_open(int * ufd,int * ifd)129 int canna_socket_open(int *ufd, int *ifd)
130 {
131   if ((canna_unixfd = canna_socket_open_unix()) == -1)
132     m_msg("unix domain not created.\n");
133   if ((canna_inetfd = canna_socket_open_inet()) == -1)
134     m_msg("inet domain not created.\n");
135 
136   if (canna_unixfd == -1 || canna_inetfd == -1)
137     return -1;
138 
139   *ufd = canna_unixfd;
140   *ifd = canna_inetfd;
141 
142   return 0;
143 }
144 
canna_socket_close()145 int canna_socket_close()
146 {
147   close(canna_unixfd);
148   close(canna_inetfd);
149 
150   unlink(CANNA_UNIX_DOMAIN_PATH);
151 
152   return 0;
153 }
154 
155 /*
156  * canna_socket_accept_new_connection : ��³�׵�������
157  *                                      fd = canna_unixfd or canna_inetfd
158  *                                    : �ե�����ǥ�������ץ����֤�
159  */
160 
canna_socket_accept_new_connection(int fd)161 static int canna_socket_accept_new_connection(int fd)
162 {
163   int i, newfd;
164   int localhost_inaddr, myhost_inaddr, *ip;
165   char buf[128], *host = NULL;
166   int size;
167   struct sockaddr_un addr_un;
168   struct sockaddr_in addr_in;
169   struct hostent *hp;
170 
171 
172   size = sizeof(struct sockaddr_un);
173 
174   if ((newfd = accept(fd, (struct sockaddr *)(&addr_un), &size)) < 0) {
175     m_msg("Cannot open new socket. Connection refused.\n");
176     return -1;
177   }
178 
179   if (addr_un.sun_family == AF_INET) {
180     memcpy(&addr_in, (struct sockaddr *)(&addr_un),sizeof(struct sockaddr_in));
181 
182     if (gethostname(buf, 128) == 0) {
183       if ((hp = gethostbyname(buf)) != NULL) {
184 	ip = (int *)(hp->h_addr_list[0]);
185 	myhost_inaddr = *ip;
186       } else {
187 	myhost_inaddr = 0;
188       }
189     } else {
190       myhost_inaddr = 0;
191     }
192 
193     if ((hp = gethostbyname("localhost")) != NULL) {
194       ip = (int *)(hp->h_addr_list[0]);
195       localhost_inaddr = *ip;
196     } else {
197       localhost_inaddr = 0;
198     }
199 
200     if (addr_in.sin_addr.s_addr != myhost_inaddr &&
201 	addr_in.sin_addr.s_addr != localhost_inaddr) {
202       m_netaddr2ascii(addr_in.sin_addr.s_addr, buf);
203 
204       m_msg("REFUSE THE CONNECTION REQUEST FROM %s.\n", buf);
205       close(newfd);
206       return -1;
207     } else {
208       m_netaddr2ascii(addr_in.sin_addr.s_addr, buf);
209 
210       hp = gethostbyaddr((char *)&addr_in.sin_addr, sizeof(struct in_addr),
211 			 AF_INET);
212 
213       if (hp && hp->h_name)
214 	host = strdup(hp->h_name);
215       else
216 	host = strdup(buf);
217     }
218   } else {
219     host = strdup("UNIX");
220   }
221 
222   for (i = USER_CLIENT; i < MAX_CLIENT_NUM; i++) {
223     if (client[i].sockfd == -1) {
224       client[i].sockfd = newfd;
225       client[i].host = host;
226       client[i].user[0] = 0;
227 
228       m_msg("New client #%d@%s accepted.\n", i, host);
229 
230       return 0;
231     }
232   }
233 
234   m_msg("Too many users. Connection from %s refused.\n", host);
235   close(newfd);
236 
237   if (host != NULL)
238     free(host);
239 
240   return -1;
241 }
242 
243 /*
244  * canna_socket_check_connection : ��³��ͭ����Ĵ�٤�
245  */
246 
canna_socket_check_connection()247 static int canna_socket_check_connection()
248 {
249   struct timeval tv;
250   fd_set set;
251   int i;
252 
253   for (i = USER_CLIENT; i < MAX_CLIENT_NUM; i++) {
254     if (client[i].sockfd != -1) {
255       FD_ZERO(&set);
256       FD_SET(client[i].sockfd, &set);
257 
258       tv.tv_sec = tv.tv_usec = 0;
259 
260       if (select(client[i].sockfd + 1, &set, NULL, NULL, &tv) < 0)
261 	client[i].need_terminate = TRUE; /* main.c �ǽ�λ�������Ƥ�餦 */
262     }
263   }
264 
265   return 0;
266 }
267 
canna_socket_wait_trigger()268 int canna_socket_wait_trigger()
269 {
270   fd_set set;
271   int i;
272   int maxfd = 0;
273 
274   FD_ZERO(&set);
275 
276   for (i = USER_CLIENT; i < MAX_CLIENT_NUM; i++)
277     if (client[i].sockfd != -1) {
278       FD_SET(client[i].sockfd, &set);
279       maxfd = client[i].sockfd > maxfd ? client[i].sockfd : maxfd;
280     }
281   if (canna_unixfd != -1) FD_SET(canna_unixfd, &set);
282   if (canna_inetfd != -1) FD_SET(canna_inetfd, &set);
283   if (canna_unixfd > maxfd) maxfd = canna_unixfd;
284   if (canna_inetfd > maxfd) maxfd = canna_inetfd;
285 
286   if (select(maxfd + 1, &set, NULL, NULL, NULL) < 0) {
287     if (errno == EBADF)
288       canna_socket_check_connection();
289     return -1;
290   }
291 
292   for (i = USER_CLIENT; i < MAX_CLIENT_NUM; i++)
293     if (client[i].sockfd != -1)
294       if (FD_ISSET(client[i].sockfd, &set))
295 	client[i].data_received = 1;
296 
297   if (canna_unixfd != -1 && FD_ISSET(canna_unixfd, &set))
298     canna_socket_accept_new_connection(canna_unixfd);
299 
300   if (canna_inetfd != -1 && FD_ISSET(canna_inetfd, &set))
301     canna_socket_accept_new_connection(canna_inetfd);
302 
303   return 0;
304 }
305