ARB
servercntrl.cxx
Go to the documentation of this file.
1 // ============================================================= //
2 // //
3 // File : servercntrl.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // ============================================================= //
10 
11 #include <servercntrl.h>
12 
13 #include <client_privat.h>
14 #include <client.h>
15 
16 #include <arbdb.h>
17 #include <arb_file.h>
18 #include <arb_sleep.h>
19 #include <ut_valgrinded.h>
20 
21 /* The following lines go to servercntrl.h
22  * edit here, not there!!
23  * call 'make proto' to update
24  */
25 
26 // AISC_MKPT_PROMOTE:#ifndef ARBDB_BASE_H
27 // AISC_MKPT_PROMOTE:#include <arbdb_base.h>
28 // AISC_MKPT_PROMOTE:#endif
29 // AISC_MKPT_PROMOTE:
30 // AISC_MKPT_PROMOTE:struct arb_params {
31 // AISC_MKPT_PROMOTE: char *species_name;
32 // AISC_MKPT_PROMOTE: char *extended_name;
33 // AISC_MKPT_PROMOTE: char *alignment;
34 // AISC_MKPT_PROMOTE: char *default_file;
35 // AISC_MKPT_PROMOTE: char *field;
36 // AISC_MKPT_PROMOTE: const char *field_default;
37 // AISC_MKPT_PROMOTE:
38 // AISC_MKPT_PROMOTE: int read_only;
39 // AISC_MKPT_PROMOTE:
40 // AISC_MKPT_PROMOTE: char *job_server;
41 // AISC_MKPT_PROMOTE: char *db_server;
42 // AISC_MKPT_PROMOTE: char *mgr_server;
43 // AISC_MKPT_PROMOTE: char *pt_server;
44 // AISC_MKPT_PROMOTE:
45 // AISC_MKPT_PROMOTE: char *tcp;
46 // AISC_MKPT_PROMOTE:};
47 // AISC_MKPT_PROMOTE:
48 // AISC_MKPT_PROMOTE:enum SpawnMode {
49 // AISC_MKPT_PROMOTE: WAIT_FOR_TERMINATION,
50 // AISC_MKPT_PROMOTE: SPAWN_ASYNCHRONOUS,
51 // AISC_MKPT_PROMOTE: SPAWN_DAEMONIZED,
52 // AISC_MKPT_PROMOTE:};
53 
54 #if defined(AISC_MAGIC_NUMBER)
55 # undef AISC_MAGIC_NUMBER
56 #endif
57 
58 
59 #define TRIES 1
60 
61 static struct gl_struct {
64 
66  : link(NULp), com(0x10000*1) // faked type id (matches main object, e.g. AN_MAIN or PT_MAIN)
67  { }
69 
70 
71 inline void make_async_call(char*& command) {
72  freeset(command, GBS_global_string_copy("( %s ) &", command));
73 }
74 
75 char *createCallOnSocketHost(const char *host, const char *remotePrefix, const char *command, SpawnMode spawnmode, const char *logfile) {
90  arb_assert((remotePrefix[0] == 0) || (strchr(remotePrefix, 0)[-1] == '/'));
91  arb_assert(correlated(spawnmode == SPAWN_DAEMONIZED, logfile));
92 
93  char *call = NULp;
94  if (host && host[0]) {
95  const char *hostPort = strchr(host, ':');
96  char *hostOnly = ARB_strpartdup(host, hostPort ? hostPort-1 : NULp);
97 
98  if (hostOnly[0] && !GB_host_is_local(hostOnly)) {
99  char *quotedRemoteCommand = GBK_singlequote(GBS_global_string("%s%s", remotePrefix, command));
100  call = GBS_global_string_copy("ssh %s -n %s", hostOnly, quotedRemoteCommand);
101  free(quotedRemoteCommand);
102  }
103  free(hostOnly);
104  }
105 
106  if (!call) {
107  call = ARB_strdup(command);
108  make_valgrinded_call(call); // only on local host
109  }
110 
111  switch (spawnmode) {
113  break;
114 
115  case SPAWN_ASYNCHRONOUS:
116  make_async_call(call);
117  break;
118 
119  case SPAWN_DAEMONIZED: {
120  char *quotedLogfile = GBK_singlequote(logfile);
121  char *quotedDaemonizingCall = GBK_singlequote(GBS_global_string("nohup %s >> %s 2>&1 & disown", call, quotedLogfile));
122 
123  freeset(call, GBS_global_string_copy("bash -c %s", quotedDaemonizingCall));
124 
125  free(quotedDaemonizingCall);
126  free(quotedLogfile);
127  break;
128  }
129  }
130 
131  return call;
132 }
133 
134 GB_ERROR arb_start_server(const char *arb_tcp_env, int do_sleep) {
135  const char *tcp_id;
136  GB_ERROR error = NULp;
137 
138  if (!(tcp_id = GBS_read_arb_tcp(arb_tcp_env))) {
139  error = GB_await_error();
140  }
141  else {
142  const char *server = strchr(tcp_id, 0) + 1;
143  char *serverparams = NULp;
144 
145  /* concatenate all params behind server
146  Note : changed behavior on 2007/Mar/09 -- ralf
147  serverparams now is one space if nothing defined in arb_tcp.dat
148  (previously was same as 'server' - most likely a bug)
149  */
150  {
151  const char *param = strchr(server, 0)+1;
152  size_t plen = strlen(param);
153  size_t alllen = 0;
154 
155  while (plen) {
156  param += plen+1;
157  alllen += plen+1;
158  plen = strlen(param);
159  }
160 
161  ARB_alloc(serverparams, alllen+1);
162  {
163  char *sp = serverparams;
164 
165  param = strchr(server, 0)+1;
166  plen = strlen(param);
167  if (!plen) sp++;
168  else do {
169  memcpy(sp, param, plen);
170  sp[plen] = ' ';
171  sp += plen+1;
172  param += plen+1;
173  plen = strlen(param);
174  } while (plen);
175  sp[-1] = 0;
176  }
177  }
178 
179  {
180  char *command = NULp;
181  const char *port = strchr(tcp_id, ':');
182 
183  if (!port) {
184  error = GB_export_errorf("Error: Missing ':' in socket definition of '%s' in file $(ARBHOME)/lib/arb_tcp.dat", arb_tcp_env);
185  }
186  else {
187  // When arb is called from arb_launcher, ARB_SERVER_LOG gets set to the name of a logfile.
188  // If ARB_SERVER_LOG is set here -> start servers daemonized here (see #492 for motivation)
189 
190  const char *serverlog = GB_getenv("ARB_SERVER_LOG");
191  SpawnMode spawnmode = serverlog ? SPAWN_DAEMONIZED : SPAWN_ASYNCHRONOUS;
192  char *plainCommand = GBS_global_string_copy("%s %s '-T%s'", server, serverparams, port); // Note: quotes around -T added for testing only (remove@will)
193  command = createCallOnSocketHost(tcp_id, "$ARBHOME/bin/", plainCommand, spawnmode, serverlog);
194  free(plainCommand);
195  }
196 
197  if (!error) {
198  error = GBK_system(command);
199  if (do_sleep) ARB_sleep(5, SEC);
200  }
201  free(command);
202  }
203  free(serverparams);
204  }
205  return error;
206 }
207 
208 static GB_ERROR arb_wait_for_server(const char *arb_tcp_env, const char *tcp_id, int magic_number, struct gl_struct *serverctrl, int wait) {
209  GB_ERROR error = NULp;
210  serverctrl->link = aisc_open(tcp_id, serverctrl->com, magic_number, &error);
211 
212  if (!error && !serverctrl->link) { // no server running -> start one
213  error = arb_start_server(arb_tcp_env, 0);
214  while (!error && !serverctrl->link && wait) {
215  ARB_sleep(1, SEC);
216  wait--;
217  if ((wait%10) == 0 && wait>0) {
218  printf("Waiting for server '%s' to come up (%i seconds left)\n", arb_tcp_env, wait);
219  }
220  serverctrl->link = aisc_open(tcp_id, serverctrl->com, magic_number, &error);
221  }
222  }
223 
224  return error;
225 }
226 
227 static GB_ERROR check_server_selected(const char *arb_tcp_env) {
228  // check whether arb_tcp_env (normally created by GBS_ptserver_tag for pt-servers)
229  // indicates that no pt-server has been selected by user.
230  //
231  // if so -> provide simple error to reduce confusion.
232 
233  if (strcmp(arb_tcp_env, "ARB_PT_SERVER-1") == 0) {
234  return "No pt-server has been selected.";
235  }
236  return NULp;
237 }
238 
239 GB_ERROR arb_look_and_start_server(long magic_number, const char *arb_tcp_env) {
241 
242  GB_ERROR error = check_server_selected(arb_tcp_env);
243  if (!error) {
244  const char *tcp_id = GBS_read_arb_tcp(arb_tcp_env);
245  const char *arb_tcp_dat = "$(ARBHOME)/lib/arb_tcp.dat";
246 
247  if (!tcp_id) {
248  error = GBS_global_string("Entry '%s' not found in %s (%s)", arb_tcp_env, arb_tcp_dat, GB_await_error());
249  }
250  else {
251  const char *file = GBS_scan_arb_tcp_param(tcp_id, "-d"); // find parameter behind '-d'
252 
253  if (!file) {
254  error = GBS_global_string("Parameter -d missing for entry '%s' in %s", arb_tcp_env, arb_tcp_dat);
255  }
256  else {
257  if (strcmp(file, "!ASSUME_RUNNING") == 0) {
258  // assume pt-server is running on a host, w/o access to common network drive
259  // i.e. we cannot check for the existence of the database file
260  }
261  else if (GB_size_of_file(file) <= 0) {
262  if (strncmp(arb_tcp_env, "ARB_NAME_SERVER", 15) == 0) {
263  char *dir = ARB_strdup(file);
264  char *lastSlash = strrchr(dir, '/');
265 
266  if (lastSlash) {
267  lastSlash[0] = 0; // cut off file
268  {
269  const char *copy_cmd = GBS_global_string("cp %s/names.dat.template %s", dir, file);
270  error = GBK_system(copy_cmd);
271  }
272  if (!error && GB_size_of_file(file) <= 0) {
273  error = GBS_global_string("Cannot copy nameserver template (%s/names.dat.template missing?)", dir);
274  }
275  }
276  else {
277  error = GBS_global_string("Can't determine directory from '%s'", dir);
278  }
279  free(dir);
280  }
281  else if (strncmp(arb_tcp_env, "ARB_PT_SERVER", 13) == 0) {
282  const char *nameOnly = strrchr(file, '/');
283  if (!nameOnly) nameOnly = file;
284 
285  error = GBS_global_string("PT_server '%s' has not been created yet.\n"
286  " To create it follow these steps:\n"
287  " 1. Start ARB on the whole database you want to use for probe match/design\n"
288  " 2. Go to ARB_NTREE/Probes/PT_SERVER Admin\n"
289  " 3. Select '%s' and press BUILD SERVER\n"
290  " 4. Wait (up to hours, depending on your DB size)\n"
291  " 5. Meanwhile read the help file: PT_SERVER: What Why and How",
292  file, nameOnly);
293  }
294  else {
295  error = GBS_global_string("The file '%s' is missing. \nUnable to start %s", file, arb_tcp_env);
296  }
297  }
298  }
299 
300  if (!error) {
301  error = arb_wait_for_server(arb_tcp_env, tcp_id, magic_number, &glservercntrl, 20);
302 
303  if (!error) {
304  if (!glservercntrl.link) { // couldn't start server
305  error = // |
306  "ARB has problems to start a server! Possible reasons may be one\n"
307  "or several of the following list:\n"
308  "- the tcp_id (socket number) is already used by another program\n"
309  " (doesnt apply to user-specific PTSERVERs; check $ARBHOME/lib/arb_tcp.dat versus /etc/services)\n"
310  "- the server exited with error or has crashed.\n"
311  " In case of PTSERVER, the failure might be caused by:\n"
312  " - missing database in $ARBHOME/lib/pts/* (solution: update ptserver database)\n"
313  " - wrong permissions of $ARBHOME/lib/pts/* (no read access)\n"
314  " If you recently installed a new arb version, arb will continue\n"
315  " to use your previous 'arb_tcp.dat', which might be out-of-date.\n"
316  " Backup and remove it, then restart ARB. If it works now,\n"
317  " compare your old 'arb_tcp.dat' with the new one for changes.\n"
318  "- When using remote servers: login or network problems\n"
319  ;
320  }
321  else {
324  }
325  }
326  }
327  }
328  }
329 
331  return error;
332 }
333 
334 GB_ERROR arb_look_and_kill_server(int magic_number, const char *arb_tcp_env) {
335  GB_ERROR error = check_server_selected(arb_tcp_env);
336  if (!error) {
337  const char *tcp_id = GBS_read_arb_tcp(arb_tcp_env);
338  if (!tcp_id) {
339  error = GB_await_error();
340  }
341  else {
342  const char *server = strchr(tcp_id, 0)+1;
343 
344  glservercntrl.link = aisc_open(tcp_id, glservercntrl.com, magic_number, &error);
345  if (glservercntrl.link) {
348 
349  error = GBK_system(GBS_global_string("%s -kill -T%s &", server, tcp_id));
350  }
351  else {
352  error = "Server is not running";
353  }
354  }
355  }
356  return error;
357 }
358 
359 const char *arb_look_and_start_ptserver(int magic_number, int ptserver_id, GB_ERROR& error) {
360  // return PT server info string (see GBS_read_arb_tcp for details) // @@@ fix doc
361  // or NULp (in this case 'error' is set)
362 
363  const char *result = NULp;
364  const char *server_tag = GBS_ptserver_tag(ptserver_id);
365 
366  error = arb_look_and_start_server(magic_number, server_tag);
367  if (!error) {
368  result = GBS_read_arb_tcp(server_tag);
369  if (!result) error = GB_await_error();
370  }
371  arb_assert(contradicted(result, error));
372  return result;
373 }
374 
375 
376 
378  printf("General server parameters (some maybe unused by this server):\n"
379  " -s<name> sets species name to '<name>'\n"
380  " -e<name> sets extended name to '<name>'\n"
381  " -a<ali> sets alignment to '<ali>'\n"
382  " -d<file> sets default file to '<file>'\n"
383  " -f<field>=<def> sets DB field to '<field>' (using <def> as default)\n"
384  " -r read-only mode\n"
385  " -D<server> sets DB-server to '<server>' [default = ':']\n"
386  " -J<server> sets job-server to '<server>' [default = 'ARB_JOB_SERVER']\n"
387  " -M<server> sets MGR-server to '<server>' [default = 'ARB_MGR_SERVER']\n"
388  " -P<server> sets PT-server to '<server>' [default = 'ARB_PT_SERVER']\n"
389  " -T<[host]:port> sets TCP connection to '<[host]:port>'\n"
390  );
391 }
392 
393 arb_params *arb_trace_argv(int *argc, const char **argv) {
394  arb_params *erg = ARB_calloc<arb_params>(1);
395 
396  erg->db_server = ARB_strdup(":");
397  erg->job_server = ARB_strdup("ARB_JOB_SERVER");
398  erg->mgr_server = ARB_strdup("ARB_MGR_SERVER");
399  erg->pt_server = ARB_strdup("ARB_PT_SERVER");
400 
401  int s, d;
402  for (s=d=0; s<*argc; s++) {
403  if (argv[s][0] == '-') {
404  switch (argv[s][1]) {
405  case 's': erg->species_name = ARB_strdup(argv[s]+2); break;
406  case 'e': erg->extended_name = ARB_strdup(argv[s]+2); break;
407  case 'a': erg->alignment = ARB_strdup(argv[s]+2); break;
408  case 'd': erg->default_file = ARB_strdup(argv[s]+2); break;
409  case 'f': {
410  char *eq;
411  erg->field = ARB_strdup(argv[s]+2);
412 
413  eq = strchr(erg->field, '=');
414  if (eq) {
415  erg->field_default = eq+1;
416  eq[0] = 0;
417  }
418  else {
419  erg->field_default = NULp; // this is illegal - error handling done in caller
420  }
421  break;
422  }
423  case 'r': erg->read_only = 1; break;
424  case 'J': freedup(erg->job_server, argv[s]+2); break;
425  case 'D': freedup(erg->db_server, argv[s]+2); break;
426  case 'M': freedup(erg->mgr_server, argv[s]+2); break;
427  case 'P': freedup(erg->pt_server, argv[s]+2); break;
428  case 'T': {
429  const char *ipport = argv[s]+2;
430  if (ipport[0] == ':' &&
431  ipport[1] >= '0' && ipport[1] <= '9') { // port only -> assume localhost
432  erg->tcp = GBS_global_string_copy("localhost%s", ipport);
433  }
434  else {
435  erg->tcp = ARB_strdup(ipport);
436  }
437  break;
438  }
439  default:
440  argv[d++] = argv[s];
441  break;
442  }
443  }
444  else {
445  argv[d++] = argv[s];
446  }
447  }
448  *argc = d;
449  return erg;
450 }
451 
453  free(params->species_name);
454  free(params->extended_name);
455  free(params->alignment);
456  free(params->default_file);
457  free(params->field);
458  free(params->job_server);
459  free(params->db_server);
460  free(params->mgr_server);
461  free(params->pt_server);
462  free(params->tcp);
463 
464  free(params);
465 }
466 
467 // --------------------------------------------------------------------------------
468 
469 #if defined(UNIT_TESTS) && 0
470 
471 // If you need tests in AISC_COM/C/client.c, put them here instead.
472 
473 #include <test_unit.h>
474 
475 void TEST_servercntrl() {
476  TEST_REJECT(true); // would fail if test gets activated
477 }
478 
479 #endif // UNIT_TESTS
480 
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:571
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
string result
SpawnMode
Definition: servercntrl.h:33
int aisc_close(aisc_com *link, AISC_Object &object)
Definition: client.c:249
char * field
Definition: servercntrl.h:20
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
GB_ERROR arb_look_and_start_server(long magic_number, const char *arb_tcp_env)
GB_ERROR arb_look_and_kill_server(int magic_number, const char *arb_tcp_env)
static GB_ERROR check_server_selected(const char *arb_tcp_env)
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
int read_only
Definition: servercntrl.h:23
bool GB_have_error()
Definition: arb_msg.cxx:338
char * ARB_strpartdup(const char *start, const char *end)
Definition: arb_string.h:51
char * alignment
Definition: servercntrl.h:18
AISC_Object com
Definition: servercntrl.cxx:63
long GB_size_of_file(const char *path)
Definition: arb_file.cxx:28
char * db_server
Definition: servercntrl.h:26
GB_ERROR arb_start_server(const char *arb_tcp_env, int do_sleep)
arb_params * arb_trace_argv(int *argc, const char **argv)
char * mgr_server
Definition: servercntrl.h:27
void free_arb_params(arb_params *params)
static ArbTcpDat arb_tcp_dat
Definition: adtcp.cxx:271
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
void arb_print_server_params()
char * job_server
Definition: servercntrl.h:25
const char * GBS_read_arb_tcp(const char *env)
Definition: adtcp.cxx:325
char * extended_name
Definition: servercntrl.h:17
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
const char * GBS_scan_arb_tcp_param(const char *ipPort, const char *wantedParam)
Definition: adtcp.cxx:275
char * createCallOnSocketHost(const char *host, const char *remotePrefix, const char *command, SpawnMode spawnmode, const char *logfile)
Definition: servercntrl.cxx:75
char * species_name
Definition: servercntrl.h:16
static GB_ERROR arb_wait_for_server(const char *arb_tcp_env, const char *tcp_id, int magic_number, struct gl_struct *serverctrl, int wait)
#define TEST_REJECT(cond)
Definition: test_unit.h:1330
static void error(const char *msg)
Definition: mkptypes.cxx:96
char * tcp
Definition: servercntrl.h:30
const char * field_default
Definition: servercntrl.h:21
void ARB_sleep(int amount, TimeUnit tu)
Definition: arb_sleep.h:32
aisc_com * link
Definition: servercntrl.cxx:62
const char * arb_look_and_start_ptserver(int magic_number, int ptserver_id, GB_ERROR &error)
GB_CSTR GB_getenv(const char *env)
Definition: adsocket.cxx:709
#define make_valgrinded_call(command)
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:262
char * GBK_singlequote(const char *arg)
Definition: arb_msg.cxx:599
aisc_com * aisc_open(const char *path, AISC_Object &main_obj, long magic, GB_ERROR *error)
Definition: client.c:205
static struct gl_struct glservercntrl
char * pt_server
Definition: servercntrl.h:28
#define NULp
Definition: cxxforward.h:116
bool GB_host_is_local(const char *hostname)
Definition: adsocket.cxx:746
static char * command
Definition: arb_a2ps.c:319
char * default_file
Definition: servercntrl.h:19
const char * GBS_ptserver_tag(int id)
Definition: adtcp.cxx:312
Definition: arb_sleep.h:30
void make_async_call(char *&command)
Definition: servercntrl.cxx:71
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
GB_write_int const char s
Definition: AW_awar.cxx:154