Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
EST_Server.cc
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  /* */
34  /* Author: Richard Caley (rjc@cstr.ed.ac.uk) */
35  /* -------------------------------------------------------------------- */
36  /* Code to talk to a running server. */
37  /* */
38  /*************************************************************************/
39 
40 #include "EST_system.h"
41 #include "EST_socket.h"
42 #include <csignal>
43 #include "EST_unix.h"
44 #include "EST_TKVL.h"
45 #include "EST_ServiceTable.h"
46 #include "EST_Server.h"
47 #include "EST_Pathname.h"
48 #include "EST_error.h"
49 #include "EST_Token.h"
50 #include <iomanip>
51 #include <iostream>
52 
53 static EST_Regex ipnum("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+");
54 
55 static EST_String cookie_term = "\n";
56 
57 static EST_String command_term = "\n//End//\n";
58 
59 static EST_String result_term = "\n//End//";
60 
61 static EST_String status_term = "\n";
62 
63 EST_Server::RequestHandler::RequestHandler()
64 {
65 }
66 
67 EST_Server::RequestHandler::~RequestHandler()
68 {
69 }
70 
71 EST_Server::ResultHandler::ResultHandler()
72 {
73 }
74 
75 EST_Server::ResultHandler::~ResultHandler()
76 {
77 }
78 
79 EST_Server::BufferedSocket::BufferedSocket(int socket)
80 {
81  s = socket;
82  bpos=0;
83  blen=100;
84  buffer=walloc(char, 100);
85 }
86 
87 EST_Server::BufferedSocket::~BufferedSocket()
88 {
89  if (buffer != NULL)
90  {
91  wfree(buffer);
92  buffer=NULL;
93  }
94 }
95 
96 void EST_Server::BufferedSocket::ensure(int n)
97 {
98  if (n > blen)
99  {
100  buffer= wrealloc(buffer, char, n+100);
101  blen = n+100;
102  }
103 }
104 
105 int EST_Server::BufferedSocket::read_data(void)
106 {
107 return ::read(s, buffer+bpos, blen-bpos);
108 }
109 
111 {
112  zero();
113  if (mode == sm_client)
114  initClient(name, type, trace);
115  else
116  initServer(mode, name, type, trace);
117 }
118 
119 EST_Server::EST_Server(EST_String name, EST_String type, ostream *trace)
120 {
121  zero();
122  initClient(name, type, trace);
123 }
124 
126 {
127  zero();
128  if (mode == sm_client)
129  initClient(name, type, NULL);
130  else
131  initServer(mode, name, type, NULL);
132 }
133 
135 {
136  zero();
137  initClient(name, type, NULL);
138 }
139 
140 EST_Server::EST_Server(EST_String hostname, int port, ostream *trace)
141 {
142  zero();
143  initClient(hostname, port, trace);
144 }
145 
147 {
148  zero();
149  initClient(hostname, port, NULL);
150 }
151 
153 {
154  if (connected())
155  disconnect();
156 // if (p_serv_addr)
157 // delete p_serv_addr;
158  if (p_buffered_socket)
159  delete p_buffered_socket;
160 }
161 
162 void EST_Server::zero()
163 {
164  p_serv_addr = NULL;
165  p_socket = -1;
166  p_mode = sm_unknown;
167  p_trace = NULL;
168 }
169 
170 void EST_Server::initClient(EST_String name, EST_String type, ostream *trace)
171 {
172  const EST_ServiceTable::Entry &entry = EST_ServiceTable::lookup(name, type);
173 
174  // if (&entry == EST_ServiceTable::EntryTable::default_val)
175  if (entry.port == 0)
176  EST_error("no %s called '%s' listed",
177  (const char *)type, (const char *)name);
178 
179  initClient(entry, trace);
180 }
181 
182 void EST_Server::initClient(EST_String hostname, int port, ostream *trace)
183 {
185 
186  tmp.name="<UNKNOWN>";
187  if (hostname.matches(ipnum))
188  {
189  tmp.hostname="";
190  tmp.address=hostname;
191  }
192  else
193  {
194  tmp.address="";
195  tmp.hostname=hostname;
196  }
197  tmp.port=port;
198  initClient(tmp, trace);
199 }
200 
201 void EST_Server::init(ostream *trace)
202 {
203 
204  p_trace=trace;
205 
206  if (!socket_initialise())
207  EST_sys_error("Can't Initialise Network Code");
208 
209  if (connected())
210  disconnect();
211 
212  if (p_serv_addr != NULL)
213  {
214 // delete p_serv_addr;
215  p_serv_addr = NULL;
216  }
217 }
218 
219 void EST_Server::initClient(const EST_ServiceTable::Entry &entry, ostream *trace)
220 {
221  init(trace);
222 
223  p_mode = sm_client;
224  p_entry = entry;
225 
226  struct sockaddr_in *serv_addr = new sockaddr_in;
227 
228  p_serv_addr = serv_addr;
229  struct hostent *serverhost;
230 
231  memset(serv_addr, 0, sizeof(*serv_addr));
232 
233  if (p_entry.address != "")
234  {
235  if (p_trace != NULL)
236  *p_trace << "Using address "
237  << entry.address
238  << "\n";
239 
240  serv_addr->sin_addr.s_addr = inet_addr(entry.address);
241  }
242  else
243  {
244  if (p_trace != NULL)
245  *p_trace << "Using domain name "
246  << entry.hostname
247  << "\n";
248 
249  serverhost = gethostbyname(entry.hostname);
250 
251  if (serverhost == (struct hostent *)0)
252  EST_error("lookup of host '%s' failed", (const char *)entry.hostname);
253 
254  memmove(&(serv_addr->sin_addr),serverhost->h_addr, serverhost->h_length);
255  }
256 
257  if (p_trace != NULL)
258  *p_trace << "Server is at "
259  << inet_ntoa(serv_addr->sin_addr)
260  << "\n";
261 
262  serv_addr->sin_family = AF_INET;
263  serv_addr->sin_port = htons(entry.port);
264 
265 }
266 
267 void EST_Server::initServer(Mode mode, EST_String name, EST_String type, ostream *trace)
268 {
269  init(trace);
270  p_mode = mode;
271 
272  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
273 
274  if (NOT_A_SOCKET(s))
275  EST_sys_error("Can't create socket");
276 
277  struct sockaddr_in serv_addr;
278 
279  memset(&serv_addr, 0, sizeof(serv_addr));
280 
281  serv_addr.sin_family = AF_INET;
282  serv_addr.sin_port = htons(0);
283  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
284 
285 
286  if (bind(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0)
287  EST_sys_error("bind failed");
288 
289  if (listen(s, 5) != 0)
290  EST_sys_error("listen failed");
291 
292  p_entry = EST_ServiceTable::create(name, type, s);
293  p_socket = s;
294 }
295 
296 
297 const EST_String EST_Server::name(void) const
298 { return p_entry.name; }
299 
300 const EST_String EST_Server::type(void) const
301 { return p_entry.type; }
302 
304 { return p_entry.hostname; }
305 
307 { return p_entry.address; }
308 
310 {
311  if (p_entry.hostname != "")
312  return p_entry.hostname;
313  else if (p_entry.address != "")
314  return p_entry.address;
315 
316  return "<UNKNOWN HOST>";
317 }
318 
319 int EST_Server::port(void) const
320 { return p_entry.port; }
321 
322 EST_connect_status EST_Server::connect(void)
323 {
324  if (connected())
325  EST_error("Already Connected");
326 
327  if (p_mode != sm_client)
328  EST_error("Connect is not a legal action on server end connections");
329 
330  struct sockaddr_in *serv_addr = (struct sockaddr_in *) p_serv_addr;
331 
332  p_socket = socket(serv_addr->sin_family, SOCK_STREAM, IPPROTO_TCP);
333 
334  if (NOT_A_SOCKET(p_socket))
335  return connect_system_error;
336 
337  if (p_trace != NULL)
338  *p_trace << "Connect to "
339  << inet_ntoa(serv_addr->sin_addr)
340  << ":"
341  << ntohs(serv_addr->sin_port)
342  << "\n";
343 
344  if (::connect(p_socket, (struct sockaddr *)serv_addr, sizeof(*serv_addr)) != 0)
345  {
346  int t_errno=errno; // save this so it isn't changed by close()
347  close(p_socket);
348  p_socket=-1;
349  errno=t_errno;
350  if (
351 #if !defined(SYSTEM_IS_WIN32)
352  t_errno == ECONNREFUSED ||
353 #endif
354  t_errno == EACCES
355  )
356  return connect_not_allowed_error;
357  if (
358 #if !defined(SYSTEM_IS_WIN32)
359  t_errno == ENETUNREACH ||
360  t_errno == EADDRNOTAVAIL ||
361 #endif
362  t_errno == ENOENT
363  )
364  return connect_not_found_error;
365  }
366 
367  p_buffered_socket = new BufferedSocket(p_socket);
368 
369  if (p_entry.cookie != "" && p_entry.cookie != "none")
370  write(*p_buffered_socket, "//"+p_entry.cookie, cookie_term);
371 
372  return connect_ok;
373 }
374 
376 {
377  return p_socket >=0;
378 }
379 
380 EST_connect_status EST_Server::disconnect(void)
381 {
382  if (!connected())
383  EST_error("Not Connected");
384 
385  if (p_trace)
386  {
387  if (p_mode == sm_client)
388  *p_trace << "Disconnect from "
389  << p_entry.name
390  << "\n";
391  else
392  *p_trace << "Close down service "
393  << p_entry.name
394  << "\n";
395  }
396 
397  if (p_buffered_socket)
398  {
399  delete p_buffered_socket;
400  p_buffered_socket = NULL;
401  }
402 
403  close(p_socket);
404  p_socket=-1;
405 
406  return connect_ok;
407 }
408 
409 bool EST_Server::parse_command(const EST_String command,
410  EST_String &package,
411  EST_String &operation,
412  EST_Server::Args &arguments)
413 {
414  (void)command;
415  (void)package;
416  (void)operation;
417  (void)arguments;
418  return false;
419 }
420 
421 EST_String EST_Server::build_command(const EST_String package,
422  const EST_String operation,
423  const EST_Server::Args &arguments)
424 {
425  (void)package;
426  (void)operation;
427  (void)arguments;
428  return "";
429 }
430 
431 bool EST_Server::parse_result(const EST_String resultString,
432  EST_Server::Result &res)
433 {
434  res.set("STRING", resultString);
435  return false;
436 }
437 
438 EST_String EST_Server::build_result(const EST_Server::Result &res)
439 {
440  (void)res;
441  return "";
442 }
443 
444 
445 
446 bool EST_Server::execute(const EST_String package,
447  const EST_String operation,
448  const EST_Server::Args &args,
449  EST_Server::ResultHandler &handler)
450 {
451 
452  EST_String command = build_command(package, operation, args);
453 
454  return execute(command, handler);
455 }
456 
457 static int server_died;
458 static void server_died_fn(int x)
459 {
460  (void)x;
461  server_died=1;
462 }
463 
464 void EST_Server::write(BufferedSocket &s, const EST_String string, const EST_String term)
465 {
466  EST_String termed;
467 
468  const char *data;
469  int l, p=0, n;
470 
471  if (term != "")
472  {
473  termed = EST_String::cat(string, term);
474  data = termed;
475  l = termed.length();
476  }
477  else
478  {
479  data = string;
480  l = string.length();
481  }
482 
483 
484  server_died=0;
485 #if !defined(SYSTEM_IS_WIN32)
486  void (*old)(int) = signal(SIGPIPE, server_died_fn);
487 #endif
488 
489  while(l>0)
490  if ((n=::write(s.s, data+p, l))>0)
491  {
492  if (p_trace)
493  *p_trace << "wrote " << n << " chars\n";
494  l -= n;
495  p += n;
496  }
497  else
498  {
499 #if !defined(SYSTEM_IS_WIN32)
500  signal(SIGPIPE, old);
501 #endif
502  EST_sys_error("Failed while writing to %s", (const char *)p_entry.type);
503  }
504 
505 #if !defined(SYSTEM_IS_WIN32)
506  signal(SIGPIPE, old);
507 #endif
508 
509  if (server_died)
510  EST_error("Failed while writing to %s", (const char *)p_entry.type);
511 }
512 
513 EST_String EST_Server::read_data(BufferedSocket &sock, const EST_String end, int &eof)
514 {
515  EST_String result(sock.buffer, 0, sock.bpos);
516  int endpos;
517 
518  eof=0;
519  sock.bpos=0;
520 
521  while ((endpos=result.index(end, 0))<0 && 1==1)
522  {
523  int n=sock.read_data();
524 
525  if ( n== 0 )
526  {
527  eof=1;
528  return "EOF";
529  }
530 
531  if (n<0)
532  EST_sys_error("Failed to read from %s %d", (const char *)p_entry.type, errno);
533 
534  EST_String bit(sock.buffer, 0, n+sock.bpos);
535 
536  if (p_trace)
537  *p_trace << "read " << n << " chars '" << bit << "'\n";
538 
539  result += bit;
540 
541  sock.bpos=0;
542  }
543 
544  sock.ensure(result.length()-endpos);
545 
546  memcpy(sock.buffer,
547  (const char *)result+endpos+end.length(),
548  result.length()-endpos-end.length());
549 
550  sock.bpos=result.length()-endpos-end.length();
551 
552  result=result.at(0, endpos);
553 
554  if (p_trace)
555  *p_trace << "Got '"
556  << result
557  << "'\n"
558  << "Left '"
559  << EST_String(sock.buffer, 0, sock.bpos)
560  << "'\n";
561 
562  return result;
563 }
564 
565 bool EST_Server::execute(const EST_String command,
566  EST_Server::ResultHandler &handler)
567 {
568  if (!connected())
569  EST_error("Must connect to %s before calling execute.", (const char *)p_entry.type);
570 
571  handler.server=this;
572  Result &res = handler.res;
573 
574  if (p_trace)
575  *p_trace << "Sending command "
576  << command
577  << " to "
578  << p_entry.type
579  << "\n";
580 
581  write(*p_buffered_socket, command, command_term);
582 
583  int eof;
584 
585  EST_String result = read_data(*p_buffered_socket, result_term, eof);
586  if (eof)
587  {
588  res.set("ERROR", "server closed connection");
589  handler.resString=result;
590  handler.process();
591  return FALSE;
592  }
593 
594  EST_String status = read_data(*p_buffered_socket, status_term, eof);
595  if (eof)
596  {
597  res.set("ERROR", "server closed connection");
598  handler.resString=result;
599  handler.process();
600  return FALSE;
601  }
602 
603 
604  if (status == "ERROR")
605  {
606  res.set("ERROR", result);
607  handler.resString=result;
608  handler.process();
609  return FALSE;
610  }
611  else if (!parse_result(result, res))
612  {
613  res.set("ERROR", "Server returned bad result '"+result+"'");
614  handler.resString=result;
615  handler.process();
616  return FALSE;
617  }
618 
619  handler.resString=result;
620  handler.process();
621  return TRUE;
622 }
623 
624 void EST_Server::run(EST_Server::RequestHandler &handler)
625 {
626  if (!connected())
627  EST_error("Server disconnected", (const char *)p_entry.type);
628 
629  handler.server=this;
630 
631  switch(p_mode)
632  {
633  case sm_sequential:
634  run_sequential(handler);
635  break;
636 
637  default:
638  EST_error("Server type %d not yet implemented", (int)p_mode);
639  break;
640  }
641 
642 }
643 
644 void EST_Server::run_sequential(EST_Server::RequestHandler &handler)
645 {
646  int csocket=0;
647  struct sockaddr_in sin;
648  socklen_t sin_size = sizeof(sin);
649 
650  while (connected() &&
651  (csocket = accept(p_socket, (struct sockaddr *) &sin,
652  &sin_size))>=0)
653  {
654  if (p_trace)
655  *p_trace << "connection " << csocket << "\n";
656 
657  BufferedSocket bs(csocket);
658 
659  if (!check_cookie(bs))
660  {
661  close(csocket);
662  continue;
663  }
664 
665  handle_client(bs, handler);
666  close(csocket);
667 
668  if (p_trace)
669  *p_trace << "Client " << csocket << " disconnected\n";
670  }
671 
672  EST_sys_error("error accepting connections");
673 }
674 
675 bool EST_Server::check_cookie(BufferedSocket &socket)
676 
677 {
678  if (p_entry.cookie == "" || p_entry.cookie == "none")
679  return TRUE;
680 
681  int eof;
682  EST_String cookie = read_data(socket, cookie_term, eof);
683 
684  if (eof || cookie.at(0, 2) != "//" || cookie.after(0,2) != p_entry.cookie)
685  {
686  EST_warning("Bad cookie '%s'", (const char *)cookie.after(0,2));
687  return FALSE;
688  }
689 
690  return TRUE;
691 }
692 
693 bool EST_Server::process_command(BufferedSocket &socket, EST_String command, RequestHandler &handler)
694 {
695  handler.requestString=command;
696 
697  if (!parse_command(command,
698  handler.package,
699  handler.operation,
700  handler.args))
701  {
702  EST_warning("Bad Command '%s'", (const char *)command);
703  return FALSE;
704  }
705 
706  EST_String error_message = handler.process();
707 
708  if (error_message != "")
709  return_error(socket, error_message);
710  else
711  return_value(socket, handler.res, TRUE);
712 
713  return TRUE;
714 }
715 
716 void EST_Server::handle_client(BufferedSocket &socket, RequestHandler &handler)
717 {
718  while (1==1)
719  {
720  int eof;
721  EST_String command=read_data(socket, command_term, eof);
722 
723  if (eof)
724  break;
725 
726  if (p_trace)
727  *p_trace << "Got command " << command << "\n";
728 
729  if (!process_command(socket, command, handler))
730  break;
731  }
732 }
733 
734 void EST_Server::return_error(BufferedSocket &socket, EST_String err)
735 {
736 
737  if (p_trace)
738  *p_trace << "error in processing: " << err << "\n";
739  write(socket, err, result_term);
740  write(socket, "ERROR", status_term);
741 }
742 
743 void EST_Server::return_value(BufferedSocket &socket, Result &res, bool final)
744 {
745  EST_String resultString = build_result(res);
746 
747  if (p_trace)
748  *p_trace << "Result: " << resultString << "\n";
749 
750  write(socket, resultString, result_term);
751  write(socket, final?"OK":"VAL", status_term);
752 }