CUBRID Engine  latest
javasp.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 
20 /*
21  * javasp.cpp - utility java stored procedure server main routine
22  *
23  */
24 
25 #ident "$Id$"
26 
27 #include "config.h"
28 
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 
34 #if !defined(WINDOWS)
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <arpa/inet.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <netdb.h>
44 #include <signal.h>
45 #else /* not WINDOWS */
46 #include <winsock2.h>
47 #include <windows.h>
48 #include <process.h>
49 #include <io.h>
50 #endif /* not WINDOWS */
51 
52 #include "environment_variable.h"
53 #include "system_parameter.h"
54 #include "error_code.h"
55 #include "error_manager.h"
56 #include "message_catalog.h"
57 #include "utility.h"
58 #include "databases_file.h"
59 #include "object_representation.h"
60 
61 #include "jsp_comm.h"
62 #include "jsp_file.h"
63 #include "jsp_sr.h"
64 
65 #include <string>
66 #include <algorithm>
67 #include <array>
68 
69 #define JAVASP_PING_LEN PATH_MAX
70 
71 #define JAVASP_PRINT_ERR_MSG(...) \
72  do {\
73  fprintf (stderr, __VA_ARGS__);\
74  }while (0)
75 
76 #if defined(WINDOWS)
77 #define NULL_DEVICE "NUL:"
78 #else
79 #define NULL_DEVICE "/dev/null"
80 #endif
81 
82 static int javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name, const std::string &path);
83 static int javasp_stop_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name);
84 static int javasp_status_server (const JAVASP_SERVER_INFO jsp_info);
85 
86 static void javasp_dump_status (FILE *fp, JAVASP_STATUS_INFO status_info);
87 static int javasp_ping_server (const int server_port, char *buf);
88 static bool javasp_is_running (const int server_port, const std::string &db_name);
89 
90 static bool javasp_is_terminated_process (int pid);
91 static void javasp_terminate_process (int pid);
92 
93 static int javasp_get_server_info (const std::string &db_name, JAVASP_SERVER_INFO &info);
94 static int javasp_check_argument (int argc, char *argv[], std::string &command, std::string &db_name);
95 static int javasp_check_database (const std::string &db_name, std::string &db_path);
96 
97 /*
98  * main() - javasp main function
99  */
100 
101 int
102 main (int argc, char *argv[])
103 {
104  int status = NO_ERROR;
105  FILE *redirect = NULL; /* for ping */
106  std::string command, db_name;
107 
108 #if defined(WINDOWS)
109  FARPROC jsp_old_hook = NULL;
110 #else
111  if (os_set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR)
112  {
113  return ER_GENERIC_ERROR;
114  }
115 #endif /* WINDOWS */
116  {
117  /*
118  * COMMON PART FOR PING AND OTHER COMMANDS
119  */
120 
121  // supress error message
123 
124  /* check arguments, get command and database name */
125  status = javasp_check_argument (argc, argv, command, db_name);
126  if (status != NO_ERROR)
127  {
128  return ER_GENERIC_ERROR;
129  }
130 
131  /* check database exists and get path name of database */
132  std::string pathname;
133  status = javasp_check_database (db_name, pathname);
134  if (status != NO_ERROR)
135  {
136  goto exit;
137  }
138 
139  /* initialize error manager for command */
140  if (command.compare ("ping") != 0)
141  {
142  /* finalize supressing error message for ping */
144 
145  /* error message log file */
146  char er_msg_file[PATH_MAX];
147  snprintf (er_msg_file, sizeof (er_msg_file) - 1, "%s_java.err", db_name.c_str ());
148  er_init (er_msg_file, ER_NEVER_EXIT);
149  }
150 
151  /* try to create info dir and get absolute path for info file; $CUBRID/var/javasp_<db_name>.info */
152  JAVASP_SERVER_INFO jsp_info = {-1, -1};
153  status = javasp_get_server_info (db_name, jsp_info);
154  if (status != NO_ERROR && command.compare ("start") != 0)
155  {
156  char info_path[PATH_MAX], err_msg[PATH_MAX + 32];
157  javasp_get_info_file (info_path, PATH_MAX, db_name.c_str ());
158  snprintf (err_msg, sizeof (err_msg), "Error while opening file (%s)", info_path);
160  goto exit;
161  }
162 
163 #if defined(WINDOWS)
164  // socket startup for windows
165  windows_socket_startup (jsp_old_hook);
166 #endif /* WINDOWS */
167 
168  /*
169  * PROCESS PING
170  */
171  if (command.compare ("ping") == 0)
172  {
173  // redirect stderr
174  if ((redirect = freopen (NULL_DEVICE, "w", stderr)) == NULL)
175  {
176  assert (false);
177  return ER_GENERIC_ERROR;
178  }
179 
180  char buffer[JAVASP_PING_LEN] = {0};
181  if ((status = javasp_ping_server (jsp_info.port, buffer)) == NO_ERROR)
182  {
183  fprintf (stdout, "%s", buffer);
184  }
185  else
186  {
187  fprintf (stdout, "NO_CONNECTION");
188  }
189  return status;
190  }
191 
192  /*
193  * BEGIN TO PROCESS FOR OTHER COMMANDS
194  */
195 
196  // load system parameter
198 
199  /* javasp command main routine */
200  if (command.compare ("start") == 0)
201  {
202  // check java stored procedure is not enabled
204  {
205  char err_msg[PATH_MAX];
206  snprintf (err_msg, PATH_MAX, "%s system parameter is not enabled", prm_get_name (PRM_ID_JAVA_STORED_PROCEDURE));
208  status = ER_SP_CANNOT_START_JVM;
209  goto exit;
210  }
211 
212  status = javasp_start_server (jsp_info, db_name, pathname);
213  if (status == NO_ERROR)
214  {
215  while (true)
216  {
217  SLEEP_MILISEC (0, 100);
218  }
219  }
220  }
221  else if (command.compare ("stop") == 0)
222  {
223  status = javasp_stop_server (jsp_info, db_name);
224  }
225  else if (command.compare ("status") == 0)
226  {
227  status = javasp_status_server (jsp_info);
228  }
229  else
230  {
231  JAVASP_PRINT_ERR_MSG ("Invalid command: %s\n", command.c_str ());
232  status = ER_GENERIC_ERROR;
233  }
234 
235 #if defined(WINDOWS)
236  // socket shutdown for windows
237  windows_socket_shutdown (jsp_old_hook);
238 #endif /* WINDOWS */
239  }
240 
241 exit:
242 
243  if (command.compare ("ping") == 0)
244  {
245  if (status != NO_ERROR)
246  {
247  fprintf (stdout, "ERROR");
248  }
249  else
250  {
251  fprintf (stdout, "NO_CONNECTION");
252  }
253 
254  if (redirect)
255  {
256  fclose (redirect);
257  }
258  }
259  else
260  {
261  if (er_has_error ())
262  {
263  JAVASP_PRINT_ERR_MSG ("%s\n", er_msg ());
264  }
265  }
266 
267  return status;
268 }
269 
270 static int
271 javasp_start_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name, const std::string &path)
272 {
273  int status = NO_ERROR;
274  int check_port = -1;
276 
277  /* trying to start javasp server for new port */
278  if (prm_port != jsp_info.port)
279  {
280  /* check javasp server is running with previously configured port number */
281  check_port = jsp_info.port;
282  }
283  else
284  {
285  /* check javasp server is running for the port number written in configuration file */
286  check_port = prm_port;
287  }
288 
289  if (javasp_is_running (check_port, db_name))
290  {
291  status = ER_GENERIC_ERROR;
292  }
293  else
294  {
295 #if !defined(WINDOWS)
296  /* create a new session */
297  setsid ();
298 #endif
299  er_clear (); // clear error before string JVM
300  status = jsp_start_server (db_name.c_str (), path.c_str (), prm_port);
301 
302  if (status == NO_ERROR)
303  {
304  JAVASP_SERVER_INFO jsp_new_info { getpid(), jsp_server_port () };
305 
306  if ((javasp_open_info_dir () && javasp_write_info (db_name.c_str (), jsp_new_info)))
307  {
308  /* succeed */
309  }
310  else
311  {
312  /* failed to write info file */
313  char info_path[PATH_MAX], err_msg[PATH_MAX + 32];
314  javasp_get_info_file (info_path, PATH_MAX, db_name.c_str ());
315  snprintf (err_msg, sizeof (err_msg), "Error while writing to file: (%s)", info_path);
317  status = ER_SP_CANNOT_START_JVM;
318  }
319  }
320  }
321 
322  return status;
323 }
324 
325 static int
326 javasp_stop_server (const JAVASP_SERVER_INFO jsp_info, const std::string &db_name)
327 {
328  SOCKET socket = INVALID_SOCKET;
329  int status = NO_ERROR;
330 
331  socket = jsp_connect_server (jsp_info.port);
332  if (socket != INVALID_SOCKET)
333  {
334  char *buffer = NULL;
335  int req_size = (int) sizeof (int);
336  int nbytes;
337 
338  int stop_code = 0xFF;
339  nbytes = jsp_writen (socket, (void *) &stop_code, (int) sizeof (int));
340  if (nbytes != (int) sizeof (int))
341  {
343  status = er_errid ();
344  }
345  jsp_disconnect_server (socket);
346 
347  if (!javasp_is_terminated_process (jsp_info.pid))
348  {
349  javasp_terminate_process (jsp_info.pid);
350  }
351 
352  javasp_reset_info (db_name.c_str ());
353  }
354 
355  return status;
356 }
357 
358 static int
360 {
361  int status = NO_ERROR;
362  char *buffer = NULL;
363  SOCKET socket = INVALID_SOCKET;
364 
365  socket = jsp_connect_server (jsp_info.port);
366  if (socket != INVALID_SOCKET)
367  {
368  char *ptr = NULL;
369  OR_ALIGNED_BUF (OR_INT_SIZE * 2) a_request;
370  char *request = OR_ALIGNED_BUF_START (a_request);
371 
372  ptr = or_pack_int (request, SP_CODE_UTIL_STATUS);
374 
375  int nbytes = jsp_writen (socket, request, (int) sizeof (int) * 2);
376  if (nbytes != (int) sizeof (int) * 2)
377  {
379  status = er_errid ();
380  goto exit;
381  }
382 
383  int res_size = 0;
384  nbytes = jsp_readn (socket, (char *) &res_size, (int) sizeof (int));
385  if (nbytes != (int) sizeof (int))
386  {
388  status = er_errid ();
389  goto exit;
390  }
391  res_size = ntohl (res_size);
392 
393  buffer = (char *) malloc (res_size);
394  if (buffer == NULL)
395  {
396  status = ER_OUT_OF_VIRTUAL_MEMORY;
397  goto exit;
398  }
399 
400  nbytes = jsp_readn (socket, buffer, res_size);
401  if (nbytes != res_size)
402  {
404  status = er_errid ();
405  goto exit;
406  }
407 
408  int num_args = 0;
409  JAVASP_STATUS_INFO status_info;
410 
411  status_info.pid = jsp_info.pid;
412  ptr = or_unpack_int (buffer, &status_info.port);
413  ptr = or_unpack_string_nocopy (ptr, &status_info.db_name);
414  ptr = or_unpack_int (ptr, &num_args);
415  for (int i = 0; i < num_args; i++)
416  {
417  char *arg = NULL;
418  ptr = or_unpack_string_nocopy (ptr, &arg);
419  status_info.vm_args.push_back (std::string (arg));
420  }
421  jsp_disconnect_server (socket);
422  javasp_dump_status (stdout, status_info);
423  }
424 
425 exit:
426  if (buffer)
427  {
428  free_and_init (buffer);
429  }
430 
431  return status;
432 }
433 
434 static int
435 javasp_ping_server (const int server_port, char *buf)
436 {
437  OR_ALIGNED_BUF (OR_INT_SIZE * 2) a_request;
438  char *request = OR_ALIGNED_BUF_START (a_request);
439  char *ptr = NULL;
440  SOCKET socket = INVALID_SOCKET;
441 
442  socket = jsp_connect_server (server_port);
443  if (socket != INVALID_SOCKET)
444  {
445  ptr = or_pack_int (request, SP_CODE_UTIL_PING);
447 
448  int nbytes = jsp_writen (socket, request, (int) sizeof (int) * 2);
449  if (nbytes != (int) sizeof (int) * 2)
450  {
452  goto exit;
453  }
454 
455  int res_size = 0;
456  nbytes = jsp_readn (socket, (char *) &res_size, (int) sizeof (int));
457  if (nbytes != (int) sizeof (int))
458  {
460  goto exit;
461  }
462  res_size = ntohl (res_size);
463 
464  nbytes = jsp_readn (socket, buf, res_size);
465  if (nbytes != res_size)
466  {
468  goto exit;
469  }
470  }
471 
472 exit:
473  if (socket != INVALID_SOCKET)
474  {
475  jsp_disconnect_server (socket);
476  }
477  return er_errid ();
478 }
479 
480 static void
481 javasp_dump_status (FILE *fp, JAVASP_STATUS_INFO status_info)
482 {
483  fprintf (fp, "Java Stored Procedure Server (%s, pid %d, port %d)\n", status_info.db_name, status_info.pid,
484  status_info.port);
485  auto vm_args_len = status_info.vm_args.size();
486  if (vm_args_len > 0)
487  {
488  fprintf (fp, "Java VM arguments :\n");
489  fprintf (fp, " -------------------------------------------------\n");
490  for (int i = 0; i < (int) vm_args_len; i++)
491  {
492  fprintf (fp, " %s\n", status_info.vm_args[i].c_str());
493  }
494  fprintf (fp, " -------------------------------------------------\n");
495  }
496 }
497 
498 static bool
499 javasp_is_running (const int server_port, const std::string &db_name)
500 {
501  // check server running
502  bool result = false;
503  char buffer[JAVASP_PING_LEN] = {0};
504  if (javasp_ping_server (server_port, buffer) == NO_ERROR)
505  {
506  if (db_name.compare (0, db_name.size (), buffer) == 0)
507  {
508  result = true;
509  }
510  }
511  return result;
512 }
513 
514 /*
515  * javasp_is_terminated_process () -
516  * return:
517  * pid(in):
518  * TODO there exists same function in file_io.c and util_service.c
519  */
520 static bool
522 {
523 #if defined(WINDOWS)
524  HANDLE h_process;
525 
526  h_process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
527  if (h_process == NULL)
528  {
529  return true;
530  }
531  else
532  {
533  CloseHandle (h_process);
534  return false;
535  }
536 #else /* WINDOWS */
537  if (kill (pid, 0) == -1)
538  {
539  return true;
540  }
541  else
542  {
543  return false;
544  }
545 #endif /* WINDOWS */
546 }
547 
548 static void
550 {
551 #if defined(WINDOWS)
552  HANDLE phandle;
553 
554  phandle = OpenProcess (PROCESS_TERMINATE, FALSE, pid);
555  if (phandle)
556  {
557  TerminateProcess (phandle, 0);
558  CloseHandle (phandle);
559  }
560 #else /* ! WINDOWS */
561  kill (pid, SIGTERM);
562 #endif /* ! WINDOWS */
563 }
564 
565 static int
567 {
568  if (javasp_open_info_dir ()
569  && javasp_read_info (db_name.c_str(), info))
570  {
571  return NO_ERROR;
572  }
573  else
574  {
575  return ER_GENERIC_ERROR;
576  }
577 }
578 
579 static int
580 javasp_check_database (const std::string &db_name, std::string &path)
581 {
582  int status = NO_ERROR;
583 
584  /* check database exists */
585  DB_INFO *db = cfg_find_db (db_name.c_str ());
586  if (db == NULL)
587  {
588  status = ER_GENERIC_ERROR;
589  }
590  else
591  {
592  path.assign (db->pathname);
593  cfg_free_directory (db);
594  }
595 
596  return status;
597 }
598 
599 static int
600 javasp_check_argument (int argc, char *argv[], std::string &command, std::string &db_name)
601 {
602  int status = NO_ERROR;
603 
604  /* check argument number */
605  if (argc == 3)
606  {
607  command.assign (argv[1]);
608  db_name.assign (argv[2]);
609  }
610  else if (argc == 2)
611  {
612  command.assign ("start");
613  db_name.assign (argv[1]);
614  }
615  else
616  {
617  status = ER_GENERIC_ERROR;
618  JAVASP_PRINT_ERR_MSG ("Invalid number of arguments: %d\n", argc);
619  }
620 
621  if (status == NO_ERROR)
622  {
623  /* check command */
624  std::array<std::string, 5> commands = {"start", "stop", "restart", "status", "ping"};
625  auto it = find (commands.begin(), commands.end(), command);
626  if (it == commands.end())
627  {
628  status = ER_GENERIC_ERROR;
629  JAVASP_PRINT_ERR_MSG ("Invalid command: %s\n", command.c_str ());
630  }
631  }
632 
633  return status;
634 }
#define SLEEP_MILISEC(sec, msec)
Definition: util_func.h:40
#define NO_ERROR
Definition: error_code.h:46
DB_INFO * cfg_find_db(const char *db_name)
int SOCKET
Definition: porting.h:482
int argc
Definition: dynamic_load.c:951
std::vector< std::string > vm_args
Definition: jsp_comm.h:63
static int javasp_stop_server(const JAVASP_SERVER_INFO jsp_info, const std::string &db_name)
Definition: javasp.cpp:326
#define OR_ALIGNED_BUF(size)
static void javasp_terminate_process(int pid)
Definition: javasp.cpp:549
char * or_unpack_string_nocopy(char *ptr, char **string)
int er_errid(void)
#define INVALID_SOCKET
Definition: porting.h:483
static bool javasp_is_running(const int server_port, const std::string &db_name)
Definition: javasp.cpp:499
bool javasp_read_info(const char *db_name, JAVASP_SERVER_INFO &info)
Definition: jsp_file.c:132
int er_init(const char *msglog_filename, int exit_ask)
#define ER_SP_NETWORK_ERROR
Definition: error_code.h:1130
#define NULL_DEVICE
Definition: javasp.cpp:79
#define OR_ALIGNED_BUF_START(abuf)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
bool javasp_reset_info(const char *db_name)
Definition: jsp_file.c:163
int jsp_start_server(const char *db_name, const char *path, int port)
Definition: jsp_sr.c:536
static void javasp_dump_status(FILE *fp, JAVASP_STATUS_INFO status_info)
Definition: javasp.cpp:481
#define assert(x)
void er_final(ER_FINAL_CODE do_global_final)
int prm_get_integer_value(PARAM_ID prm_id)
#define ER_GENERIC_ERROR
Definition: error_code.h:49
#define ER_SP_CANNOT_START_JVM
Definition: error_code.h:1126
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static int server_port
Definition: jsp_cl.c:109
int sysprm_load_and_init(const char *db_name, const char *conf_file, const int load_flags)
static int javasp_get_server_info(const std::string &db_name, JAVASP_SERVER_INFO &info)
Definition: javasp.cpp:566
static int javasp_ping_server(const int server_port, char *buf)
Definition: javasp.cpp:435
#define NULL
Definition: freelistheap.h:34
const char * er_msg(void)
pid_t pid
Definition: dynamic_load.c:955
#define JAVASP_PING_LEN
Definition: javasp.cpp:69
void jsp_disconnect_server(const SOCKET sockfd)
Definition: jsp_comm.c:135
char * or_unpack_int(char *ptr, int *number)
char * db_name
int jsp_writen(SOCKET fd, const void *vptr, int n)
Definition: jsp_comm.c:160
char * or_pack_int(char *ptr, int number)
static bool javasp_is_terminated_process(int pid)
Definition: javasp.cpp:521
#define ARG_FILE_LINE
Definition: error_manager.h:44
bool er_has_error(void)
static int javasp_check_database(const std::string &db_name, std::string &db_path)
Definition: javasp.cpp:580
const char ** argv
Definition: dynamic_load.c:952
#define free_and_init(ptr)
Definition: memory_alloc.h:147
int main(int argc, char *argv[])
Definition: javasp.cpp:102
bool javasp_write_info(const char *db_name, JAVASP_SERVER_INFO info)
Definition: jsp_file.c:148
bool prm_get_bool_value(PARAM_ID prm_id)
SOCKET jsp_connect_server(int server_port)
Definition: jsp_comm.c:58
#define FALSE
Definition: broker_admin.c:50
int jsp_server_port(void)
Definition: jsp_sr.c:751
bool javasp_get_info_file(char *buf, size_t len, const char *db_name)
Definition: jsp_file.c:87
void er_clear(void)
int i
Definition: dynamic_load.c:954
const char * prm_get_name(PARAM_ID prm_id)
int jsp_readn(SOCKET fd, void *vptr, int n)
Definition: jsp_comm.c:212
static int javasp_check_argument(int argc, char *argv[], std::string &command, std::string &db_name)
Definition: javasp.cpp:600
#define JAVASP_PRINT_ERR_MSG(...)
Definition: javasp.cpp:71
unsigned int ntohl(unsigned int from)
bool javasp_open_info_dir()
Definition: jsp_file.c:41
void cfg_free_directory(DB_INFO *databases)
static int javasp_status_server(const JAVASP_SERVER_INFO jsp_info)
Definition: javasp.cpp:359
SIGNAL_HANDLER_FUNCTION os_set_signal_handler(const int sig_no, SIGNAL_HANDLER_FUNCTION sig_handler)
Definition: porting.c:1333
static int javasp_start_server(const JAVASP_SERVER_INFO jsp_info, const std::string &db_name, const std::string &path)
Definition: javasp.cpp:271