1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1996,1997 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Alan Black and Richard Tobin */
34 /* Date : December 1996 */
35 /*-----------------------------------------------------------------------*/
36 /* */
37 /* Socket support to run Festival as a server process */
38 /* */
39 /* The original socket code is derived Richard Tobin's scokpipe/pipesock */
40 /* examples, but have be substantially changed to be more general */
41 /* for Festival */
42 /* */
43 /* The logging, access control, file transfer stuff are all new */
44 /* */
45 /*=======================================================================*/
46 #include <cstdlib>
47 #include <cstdio>
48 #include <cerrno>
49 #include <sys/types.h>
50 #include <cstring>
51 #include <ctime>
52 #include "EST_unix.h"
53 #include "EST_socket.h"
54 #include "festival.h"
55 #include "festivalP.h"
56
57 #define DEFAULT_MAX_CLIENTS 10
58
59 /* The folloing gives a server that never forks */
60 /* and only accepts one client at a time. This is good for */
61 /* OSs with an expensive implementation of fork and or waitpid (e.g. NT) */
62 #ifdef WIN32
63 #define SINGLE_CLIENT 1
64 #endif
65
66
67 static int client_access_check(int fd,int client);
68 static EST_String log_time_stamp(int client);
69 static void log_message(int client,const char *message);
70
71 int ft_server_socket = -1;
72 ostream *cslog = NULL;
73
festival_start_server(int port)74 int festival_start_server(int port)
75 {
76 // Never exits except by signals
77 struct sockaddr_in serv_addr;
78 int fd, fd1;
79 int statusp;
80 int client_name=0;
81 int max_clients, num_clients, pid;
82 LISP lmax_clients, llog_file;
83
84 lmax_clients = siod_get_lval("server_max_client",NULL);
85 if (lmax_clients != NULL)
86 max_clients = get_c_int(lmax_clients);
87 else
88 max_clients = DEFAULT_MAX_CLIENTS;
89 num_clients = 0;
90 llog_file = siod_get_lval("server_log_file",NULL);
91 if (llog_file == NIL)
92 cslog = cdebug;
93 else if (llog_file == siod_get_lval("t",NULL))
94 cslog = &cout;
95 else
96 cslog = new ofstream(get_c_string(llog_file),ios::app);
97
98 if (!socket_initialise())
99 {
100 festival_error();
101 }
102
103 fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
104
105 if (NOT_A_SOCKET(fd))
106 {
107 int n = socket_error();
108 cerr << "socket: socket failed (" << n << ")\n";
109
110 festival_error();
111 }
112 int one = 1;
113
114 if (setsockopt(fd, SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(int)) < 0)
115 {
116 cerr << "socket: SO_REUSEADDR failed" << endl;
117 festival_error();
118 }
119
120 memset(&serv_addr, 0, sizeof(serv_addr));
121 serv_addr.sin_family = AF_INET;
122 serv_addr.sin_port = htons(port);
123 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
124
125 if (::bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0)
126 {
127 cerr << "socket: bind failed" << endl;
128 festival_error();
129 }
130
131 if (listen(fd, 5) != 0)
132 {
133 cerr << "socket: listen failed" << endl;
134 festival_error();
135 }
136
137 #if SINGLE_CLIENT
138 log_message(0,EST_String("Festival server (non-forking) started on port ")+
139 itoString(port));
140 #else
141 log_message(0,EST_String("Festival server started on port ")+
142 itoString(port));
143 #endif
144
145 fflush(stdout);
146 fflush(stderr);
147 fflush(stdin);
148
149 while(1) // never exits except by signals
150 {
151 if((fd1 = accept(fd, 0, 0)) < 0)
152 {
153 cerr << "socket: accept failed";
154 festival_error();
155 }
156
157 client_name++;
158 if (client_access_check(fd1,client_name) == FALSE)
159 {
160 close(fd1);
161 continue;
162 }
163 #ifdef SINGLE_CLIENT
164 ft_server_socket = fd1;
165 repl_from_socket(fd1);
166 log_message(client_name,"disconnected");
167 #else
168 num_clients++;
169
170 // Fork new image of festival and call interpreter
171 if (num_clients > max_clients)
172 {
173 log_message(client_name,"failed: too many clients");
174 num_clients--;
175 }
176 else if ((pid=fork()) == 0)
177 {
178 ft_server_socket = fd1;
179 repl_from_socket(fd1);
180 log_message(client_name,"disconnected");
181 exit(0);
182 }
183 else if (pid < 0)
184 {
185 log_message(client_name,"failed to fork new client");
186 num_clients--;
187 }
188
189 while ((num_clients > 0) && (waitpid(0,&statusp,WNOHANG) != 0))
190 num_clients--;
191 #endif
192
193 close(fd1);
194 }
195
196 return 0;
197 }
198
client_access_check(int fd,int client)199 static int client_access_check(int fd,int client)
200 {
201 // Check client against various possible checks to see if they
202 // are allowed access to the server
203 LISP passwd, access_list, deny_list;
204 int client_access = TRUE;
205 struct sockaddr_in peer;
206 socklen_t addrlen=sizeof(peer);
207 struct hostent *clienthost;
208 const char *client_hostname;
209 const char *client_hostnum;
210 const char *reason = "";
211
212 getpeername(fd,(struct sockaddr *)&peer,&addrlen);
213 clienthost = gethostbyaddr((char *)&peer.sin_addr,
214 sizeof(peer.sin_addr),AF_INET);
215 client_hostnum = inet_ntoa(peer.sin_addr);
216 if (streq(client_hostnum,"0.0.0.0") || streq(client_hostnum,"127.0.0.1")) // its me !
217 client_hostname = "localhost";
218 else if (clienthost == 0) // failed to get a name
219 client_hostname = client_hostnum;
220 else
221 client_hostname = clienthost->h_name;
222
223 if (((deny_list = siod_get_lval("server_deny_list",NULL)) != NIL) &&
224 (siod_regex_member_str(client_hostname,deny_list) != NIL))
225 {
226 client_access = FALSE;
227 reason = "in deny list";
228 }
229 else if ((access_list = siod_get_lval("server_access_list",NULL)) != NIL)
230 {
231 client_access = FALSE; // by default now
232 reason = "not in access list";
233 if (siod_regex_member_str(client_hostname,access_list) != NIL)
234 {
235 reason = "";
236 client_access = TRUE;
237 }
238 }
239
240 passwd = siod_get_lval("server_passwd",NULL);
241 if ((client_access == TRUE) && (passwd != NULL))
242 {
243 char *client_passwd = walloc(char,strlen(get_c_string(passwd))+1);
244 read(fd,client_passwd,strlen(get_c_string(passwd)));
245 client_passwd[strlen(get_c_string(passwd))] = '\0';
246 if (streq(get_c_string(passwd),client_passwd))
247 client_access = TRUE;
248 else
249 {
250 client_access = FALSE;
251 reason = "bad passwd";
252 }
253 wfree(client_passwd);
254 }
255 char *message = walloc(char,20+strlen(client_hostname)+strlen(reason));
256
257 if (client_access == TRUE)
258 {
259 sprintf(message,"accepted from %s",client_hostname);
260 log_message(client,message);
261 }
262 else
263 {
264 sprintf(message,"rejected from %s %s",client_hostname,reason);
265 log_message(client,message);
266 }
267
268 wfree(message);
269
270 return client_access;
271
272 }
273
log_message(int client,const char * message)274 static void log_message(int client, const char *message)
275 {
276 // log the message in log file
277
278 *cslog << log_time_stamp(client) << message << endl;
279 }
280
log_time_stamp(int client)281 static EST_String log_time_stamp(int client)
282 {
283 // returns a string with client id, time and date
284 char lst[1024];
285 time_t thetime = time(0);
286 char *cthetime = ctime(&thetime);
287 cthetime[24] = '\0'; // get rid of \n
288
289 if (client == 0)
290 sprintf(lst,"server %s : ",cthetime);
291 else
292 sprintf(lst,"client(%d) %s : ",client,cthetime);
293
294 return lst;
295 }
296
297
298
299