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