Midas Common Functions (cm_xxx)
[The midas.h & midas.c]


Data Structures

struct  TR_CLIENT

Functions

INT cm_synchronize (DWORD *seconds)
INT cm_asctime (char *str, INT buf_size)
INT cm_time (DWORD *t)
char * cm_get_version ()
int cm_get_revision ()
INT cm_set_path (char *path)
INT cm_get_path (char *path)
INT cm_scan_experiments (void)
INT cm_delete_client_info (HNDLE hDB, INT pid)
INT cm_check_client (HNDLE hDB, HNDLE hKeyClient)
INT cm_set_client_info (HNDLE hDB, HNDLE *hKeyClient, char *host_name, char *client_name, INT hw_type, char *password, DWORD watchdog_timeout)
INT cm_get_client_info (char *client_name)
INT cm_get_environment (char *host_name, int host_name_size, char *exp_name, int exp_name_size)
INT cm_connect_experiment (const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *))
INT cm_connect_experiment1 (const char *host_name, const char *exp_name, const char *client_name, void(*func)(char *), INT odb_size, DWORD watchdog_timeout)
INT cm_list_experiments (const char *host_name, char exp_name[MAX_EXPERIMENT][NAME_LENGTH])
INT cm_select_experiment (const char *host_name, char *exp_name)
INT cm_connect_client (char *client_name, HNDLE *hConn)
INT cm_disconnect_client (HNDLE hConn, BOOL bShutdown)
INT cm_disconnect_experiment (void)
INT cm_set_experiment_database (HNDLE hDB, HNDLE hKeyClient)
INT cm_get_experiment_database (HNDLE *hDB, HNDLE *hKeyClient)
static int bm_validate_client_index (const BUFFER *buf)
INT cm_set_watchdog_params (BOOL call_watchdog, DWORD timeout)
INT cm_get_watchdog_params (BOOL *call_watchdog, DWORD *timeout)
INT cm_get_watchdog_info (HNDLE hDB, char *client_name, DWORD *timeout, DWORD *last)
INT cm_register_transition (INT transition, INT(*func)(INT, char *), INT sequence_number)
INT cm_deregister_transition (INT transition)
INT cm_set_transition_sequence (INT transition, INT sequence_number)
INT cm_register_deferred_transition (INT transition, BOOL(*func)(INT, BOOL))
INT cm_check_deferred_transition ()
int tr_compare (const void *arg1, const void *arg2)
INT cm_transition1 (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
INT cm_transition (INT transition, INT run_number, char *errstr, INT errstr_size, INT async_flag, INT debug_flag)
INT cm_yield (INT millisec)
INT cm_execute (const char *command, char *result, INT bufsize)
INT cm_shutdown (const char *name, BOOL bUnique)
INT cm_exist (const char *name, BOOL bUnique)
INT cm_cleanup (const char *client_name, BOOL ignore_timeout)


Function Documentation

static int bm_validate_client_index ( const BUFFER buf  )  [static]

dox

Definition at line 2506 of file midas.c.

Referenced by bm_cleanup(), bm_close_buffer(), bm_empty_buffers(), bm_flush_cache(), bm_push_event(), bm_receive_event(), bm_remove_event_request(), bm_send_event(), bm_skip_event(), cm_cleanup(), and cm_set_watchdog_params().

02507 {
02508    int badindex = 0;
02509    BUFFER_CLIENT *bcl = buf->buffer_header->client;
02510 
02511    if (buf->client_index < 0)
02512       badindex = 1;
02513    else if (buf->client_index > buf->buffer_header->max_client_index)
02514       badindex = 1;
02515    else {
02516       bcl = &(buf->buffer_header->client[buf->client_index]);
02517       if (bcl->name[0] == 0)
02518          badindex = 1;
02519       else if (bcl->pid != ss_getpid())
02520          badindex = 1;
02521    }
02522 
02523 #if 0
02524    printf
02525        ("bm_validate_client_index: badindex=%d, buf=%p, client_index=%d, max_client_index=%d, client_name=\'%s\', client_pid=%d, pid=%d\n",
02526         badindex, buf, buf->client_index, buf->buffer_header->max_client_index,
02527         buf->buffer_header->client[buf->client_index].name, buf->buffer_header->client[buf->client_index].pid,
02528         ss_getpid());
02529 #endif
02530 
02531    if (badindex) {
02532       static int prevent_recursion = 1;
02533       if (prevent_recursion) {
02534          prevent_recursion = 0;
02535          cm_msg(MERROR, "bm_validate_client_index",
02536                 "Invalid client index %d in buffer \'%s\'. Client name \'%s\', pid %d should be %d",
02537                 buf->client_index, buf->buffer_header->name, bcl->name, bcl->pid, ss_getpid());
02538          cm_msg(MERROR, "bm_validate_client_index",
02539                 "Maybe this client was removed by a timeout. Cannot continue, exiting.");
02540       }
02541       exit(1);
02542    }
02543 
02544    return buf->client_index;
02545 }

INT cm_asctime ( char *  str,
INT  buf_size 
)

Get time from MIDAS server and set local time.

Parameters:
str return time string
buf_size Maximum size of str
Returns:
CM_SUCCESS

Definition at line 1135 of file midas.c.

Referenced by al_trigger_alarm(), cm_transition1(), and rpc_server_dispatch().

01136 {
01137    /* if connected to server, get time from there */
01138    if (rpc_is_remote())
01139       return rpc_call(RPC_CM_ASCTIME, str, buf_size);
01140 
01141    /* return local time */
01142    strcpy(str, ss_asctime());
01143 
01144    return CM_SUCCESS;
01145 }

INT cm_check_client ( HNDLE  hDB,
HNDLE  hKeyClient 
)

Check if a client with a /system/client/xxx entry has a valid entry in the ODB client table. If not, remove that client from the /system/client tree.

Parameters:
hDB Handle to online database
hKeyClient Handle to client key
Returns:
CM_SUCCESS, CM_NO_CLIENT

Definition at line 1413 of file midas.c.

Referenced by cm_set_client_info(), cm_transition1(), and rpc_server_dispatch().

01414 {
01415    if (rpc_is_remote())
01416       return rpc_call(RPC_CM_CHECK_CLIENT, hDB, hKeyClient);
01417 
01418 #ifdef LOCAL_ROUTINES
01419    {
01420       KEY key;
01421       DATABASE_HEADER *pheader;
01422       DATABASE_CLIENT *pclient;
01423       INT i, client_pid, status, dead = 0, found = 0;
01424       char name[NAME_LENGTH];
01425 
01426       db_get_key(hDB, hKeyClient, &key);
01427       client_pid = atoi(key.name);
01428 
01429       i = sizeof(name);
01430       db_get_value(hDB, hKeyClient, "Name", name, &i, TID_STRING, TRUE);
01431 
01432       db_lock_database(hDB);
01433       if (_database[hDB - 1].attached) {
01434          pheader = _database[hDB - 1].database_header;
01435          pclient = pheader->client;
01436 
01437          /* loop through clients */
01438          for (i = 0; i < pheader->max_client_index; i++, pclient++)
01439             if (pclient->pid == client_pid) {
01440                found = 1;
01441                break;
01442             }
01443 #ifdef OS_UNIX
01444 #ifdef ESRCH
01445          if (found) {           /* check that the client is still running: PID still exists */
01446             /* Only enable this for systems that define ESRCH and hope that they also support kill(pid,0) */
01447             errno = 0;
01448             kill(client_pid, 0);
01449             if (errno == ESRCH) {
01450                cm_msg(MERROR, "cm_check_client",
01451                       "Removing client \'%s\', pid %d, index %d because this pid no longer exists",
01452                       pclient->name, client_pid, i);
01453                dead = 1;
01454             }
01455          }
01456 #endif
01457 #endif
01458 
01459          if (!found || dead) {
01460             /* client not found : delete ODB stucture */
01461             db_unlock_database(hDB);
01462 
01463             status = cm_delete_client_info(hDB, client_pid);
01464             if (status != CM_SUCCESS)
01465                cm_msg(MERROR, "cm_check_client",
01466                       "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid,
01467                       status);
01468             else
01469                cm_msg(MINFO, "cm_check_client",
01470                       "Deleted entry \'/System/Clients/%d\' for client \'%s\'", client_pid, name);
01471 
01472             return CM_NO_CLIENT;
01473          }
01474       }
01475 
01476       db_unlock_database(hDB);
01477    }
01478 #endif                          /*LOCAL_ROUTINES */
01479 
01480    return CM_SUCCESS;
01481 }

INT cm_check_deferred_transition (  ) 

Check for any deferred transition. If a deferred transition handler has been registered via the cm_register_deferred_transition function, this routine should be called regularly. It checks if a transition request is pending. If so, it calld the registered handler if the transition should be done and then actually does the transition.

Returns:
CM_SUCCESS, <error> Error from cm_transition()

Definition at line 3119 of file midas.c.

03120 {
03121    INT i, status;
03122    char str[256];
03123    static BOOL first;
03124 
03125    if (_requested_transition == 0)
03126       first = TRUE;
03127 
03128    if (_requested_transition & _deferred_transition_mask) {
03129       for (i = 0; _deferred_trans_table[i].transition; i++)
03130          if (_deferred_trans_table[i].transition == _requested_transition)
03131             break;
03132 
03133       if (_deferred_trans_table[i].transition == _requested_transition) {
03134          if (((BOOL(*)(INT, BOOL)) _deferred_trans_table[i].func) (_requested_transition, first)) {
03135             status = cm_transition(_requested_transition | TR_DEFERRED, 0, str, sizeof(str), SYNC, FALSE);
03136             if (status != CM_SUCCESS)
03137                cm_msg(MERROR, "cm_check_deferred_transition", "Cannot perform deferred transition: %s", str);
03138 
03139             /* bypass hotlink and set _requested_transition directly to zero */
03140             _requested_transition = 0;
03141 
03142             return status;
03143          }
03144          first = FALSE;
03145       }
03146    }
03147 
03148    return SUCCESS;
03149 }

INT cm_cleanup ( const char *  client_name,
BOOL  ignore_timeout 
)

Remove hanging clients independent of their watchdog timeout.

Since this function does not obey the client watchdog timeout, it should be only called to remove clients which have their watchdog checking turned off or which are known to be dead. The normal client removement is done via cm_watchdog().

Currently (Sept. 02) there are two applications for that:

  1. The ODBEdit command "cleanup", which can be used to remove clients which have their watchdog checking off, like the analyzer started with the "-d" flag for a debugging session.
  2. The frontend init code to remove previous frontends. This can be helpful if a frontend dies. Normally, one would have to wait 60 sec. for a crashed frontend to be removed. Only then one can start again the frontend. Since the frontend init code contains a call to cm_cleanup(<frontend_name>), one can restart a frontend immediately.

Added ignore_timeout on Nov.03. A logger might have an increased tiemout of up to 60 sec. because of tape operations. If ignore_timeout is FALSE, the logger is then not killed if its inactivity is less than 60 sec., while in the previous implementation it was always killed after 2*WATCHDOG_INTERVAL.

Parameters:
client_name Client name, if zero check all clients
ignore_timeout If TRUE, ignore a possible increased timeout defined by each client.
Returns:
CM_SUCCESS

Definition at line 5033 of file midas.c.

Referenced by cm_transition1(), command_loop(), main(), and rpc_server_dispatch().

05034 {
05035    if (rpc_is_remote())
05036       return rpc_call(RPC_CM_CLEANUP, client_name);
05037 
05038 #ifdef LOCAL_ROUTINES
05039    {
05040       BUFFER_HEADER *pheader = NULL;
05041       BUFFER_CLIENT *pbclient;
05042       DATABASE_HEADER *pdbheader;
05043       DATABASE_CLIENT *pdbclient;
05044       KEY *pkey;
05045       INT client_pid;
05046       INT i, j, k, status, nc;
05047       BOOL bDeleted;
05048       char str[256];
05049       DWORD interval;
05050       DWORD now = ss_millitime();
05051 
05052       /* check buffers */
05053       for (i = 0; i < _buffer_entries; i++)
05054          if (_buffer[i].attached) {
05055             /* update the last_activity entry to show that we are alive */
05056             pheader = _buffer[i].buffer_header;
05057             pbclient = pheader->client;
05058             pbclient[bm_validate_client_index(&_buffer[i])].last_activity = ss_millitime();
05059 
05060             /* now check other clients */
05061             for (j = 0; j < pheader->max_client_index; j++, pbclient++)
05062                if (j != _buffer[i].client_index && pbclient->pid &&
05063                    (client_name == NULL || client_name[0] == 0
05064                     || strncmp(pbclient->name, client_name, strlen(client_name)) == 0)) {
05065                   if (ignore_timeout)
05066                      interval = 2 * WATCHDOG_INTERVAL;
05067                   else
05068                      interval = pbclient->watchdog_timeout;
05069 
05070                   /* If client process has no activity, clear its buffer entry. */
05071                   if (interval > 0
05072                       && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
05073                      bm_lock_buffer(i + 1);
05074                      str[0] = 0;
05075 
05076                      /* now make again the check with the buffer locked */
05077                      if (interval > 0
05078                          && now > pbclient->last_activity && now - pbclient->last_activity > interval) {
05079                         sprintf(str,
05080                                 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs,TO %1.0lfs)",
05081                                 pbclient->name, pheader->name,
05082                                 (ss_millitime() - pbclient->last_activity) / 1000.0, interval / 1000.0);
05083 
05084                         bm_remove_client_locked(pheader, j);
05085                      }
05086 
05087                      bm_unlock_buffer(i + 1);
05088 
05089                      /* display info message after unlocking buffer */
05090                      if (str[0])
05091                         cm_msg(MINFO, "cm_cleanup", str);
05092 
05093                      /* go again through whole list */
05094                      j = 0;
05095                   }
05096                }
05097          }
05098 
05099       /* check online databases */
05100       for (i = 0; i < _database_entries; i++)
05101          if (_database[i].attached) {
05102             /* update the last_activity entry to show that we are alive */
05103             db_lock_database(i + 1);
05104 
05105             pdbheader = _database[i].database_header;
05106             pdbclient = pdbheader->client;
05107             pdbclient[_database[i].client_index].last_activity = ss_millitime();
05108 
05109             /* now check other clients */
05110             for (j = 0; j < pdbheader->max_client_index; j++, pdbclient++)
05111                if (j != _database[i].client_index && pdbclient->pid &&
05112                    (client_name == NULL || client_name[0] == 0
05113                     || strncmp(pdbclient->name, client_name, strlen(client_name)) == 0)) {
05114                   client_pid = pdbclient->pid;
05115                   if (ignore_timeout)
05116                      interval = 2 * WATCHDOG_INTERVAL;
05117                   else
05118                      interval = pdbclient->watchdog_timeout;
05119 
05120                   /* If client process has no activity, clear its buffer entry. */
05121 
05122                   if (interval > 0 && ss_millitime() - pdbclient->last_activity > interval) {
05123                      bDeleted = FALSE;
05124                      str[0] = 0;
05125 
05126                      /* now make again the check with the buffer locked */
05127                      if (interval > 0 && ss_millitime() - pdbclient->last_activity > interval) {
05128                         sprintf(str,
05129                                 "Client \'%s\' on \'%s\' removed by cm_cleanup (idle %1.1lfs,TO %1.0lfs)",
05130                                 pdbclient->name, pdbheader->name,
05131                                 (ss_millitime() - pdbclient->last_activity) / 1000.0, interval / 1000.0);
05132 
05133                         /* decrement notify_count for open records and clear exclusive mode */
05134                         for (k = 0; k < pdbclient->max_index; k++)
05135                            if (pdbclient->open_record[k].handle) {
05136                               pkey = (KEY *) ((char *) pdbheader + pdbclient->open_record[k].handle);
05137                               if (pkey->notify_count > 0)
05138                                  pkey->notify_count--;
05139 
05140                               if (pdbclient->open_record[k].access_mode & MODE_WRITE)
05141                                  db_set_mode(i + 1, pdbclient->open_record[k].handle,
05142                                              (WORD) (pkey->access_mode & ~MODE_EXCLUSIVE), 2);
05143                            }
05144 
05145                         /* clear entry from client structure in buffer header */
05146                         memset(&(pdbheader->client[j]), 0, sizeof(DATABASE_CLIENT));
05147 
05148                         /* calculate new max_client_index entry */
05149                         for (k = MAX_CLIENTS - 1; k >= 0; k--)
05150                            if (pdbheader->client[k].pid != 0)
05151                               break;
05152                         pdbheader->max_client_index = k + 1;
05153 
05154                         /* count new number of clients */
05155                         for (k = MAX_CLIENTS - 1, nc = 0; k >= 0; k--)
05156                            if (pheader->client[k].pid != 0)
05157                               nc++;
05158                         pdbheader->num_clients = nc;
05159 
05160                         bDeleted = TRUE;
05161                      }
05162 
05163 
05164                      /* delete client entry after unlocking db */
05165                      if (bDeleted) {
05166                         db_unlock_database(i + 1);
05167 
05168                         /* display info message after unlocking buffer */
05169                         cm_msg(MINFO, "cm_cleanup", str);
05170 
05171                         status = cm_delete_client_info(i + 1, client_pid);
05172                         if (status != CM_SUCCESS)
05173                            cm_msg(MERROR, "cm_cleanup", "cannot delete client info");
05174 
05175                         /* re-lock database */
05176                         db_lock_database(i + 1);
05177                         pdbheader = _database[i].database_header;
05178                         pdbclient = pdbheader->client;
05179 
05180                         /* go again though whole list */
05181                         j = 0;
05182                      }
05183                   }
05184                }
05185 
05186             db_unlock_database(i + 1);
05187          }
05188 
05189    }
05190 #endif                          /* LOCAL_ROUTINES */
05191 
05192    return CM_SUCCESS;
05193 }

INT cm_connect_client ( char *  client_name,
HNDLE *  hConn 
)

Connect to a MIDAS client of the current experiment

For internal use only.

Parameters:
client_name Name of client to connect to. This name is set by the other client via the cm_connect_experiment call.
hConn Connection handle
Returns:
CM_SUCCESS, CM_NO_CLIENT

Definition at line 2220 of file midas.c.

Referenced by command_loop(), do_jrpc_rev0(), interprete(), and show_cnaf_page().

02221 {
02222    HNDLE hDB, hKeyRoot, hSubkey, hKey;
02223    INT status, i, length, port;
02224    char name[NAME_LENGTH], host_name[HOST_NAME_LENGTH];
02225 
02226    /* find client entry in ODB */
02227    cm_get_experiment_database(&hDB, &hKey);
02228 
02229    status = db_find_key(hDB, 0, "System/Clients", &hKeyRoot);
02230    if (status != DB_SUCCESS)
02231       return status;
02232 
02233    i = 0;
02234    do {
02235       /* search for client with specific name */
02236       status = db_enum_key(hDB, hKeyRoot, i++, &hSubkey);
02237       if (status == DB_NO_MORE_SUBKEYS)
02238          return CM_NO_CLIENT;
02239 
02240       status = db_find_key(hDB, hSubkey, "Name", &hKey);
02241       if (status != DB_SUCCESS)
02242          return status;
02243 
02244       length = NAME_LENGTH;
02245       status = db_get_data(hDB, hKey, name, &length, TID_STRING);
02246       if (status != DB_SUCCESS)
02247          return status;
02248 
02249       if (equal_ustring(name, client_name)) {
02250          status = db_find_key(hDB, hSubkey, "Server Port", &hKey);
02251          if (status != DB_SUCCESS)
02252             return status;
02253 
02254          length = sizeof(INT);
02255          status = db_get_data(hDB, hKey, &port, &length, TID_INT);
02256          if (status != DB_SUCCESS)
02257             return status;
02258 
02259          status = db_find_key(hDB, hSubkey, "Host", &hKey);
02260          if (status != DB_SUCCESS)
02261             return status;
02262 
02263          length = sizeof(host_name);
02264          status = db_get_data(hDB, hKey, host_name, &length, TID_STRING);
02265          if (status != DB_SUCCESS)
02266             return status;
02267 
02268          /* client found -> connect to its server port */
02269          return rpc_client_connect(host_name, port, client_name, hConn);
02270       }
02271 
02272 
02273    } while (TRUE);
02274 }

INT cm_connect_experiment ( const char *  host_name,
const char *  exp_name,
const char *  client_name,
void(*)(char *)  func 
)

This function connects to an existing MIDAS experiment. This must be the first call in a MIDAS application. It opens three TCP connection to the remote host (one for RPC calls, one to send events and one for hot-link notifications from the remote host) and writes client information into the ODB under /System/Clients.

Attention:
All MIDAS applications should evaluate the MIDAS_SERVER_HOST and MIDAS_EXPT_NAME environment variables as defaults to the host name and experiment name (see Environment variables). For that purpose, the function cm_get_environment() should be called prior to cm_connect_experiment(). If command line parameters -h and -e are used, the evaluation should be done between cm_get_environment() and cm_connect_experiment(). The function cm_disconnect_experiment() must be called before a MIDAS application exits.
#include <stdio.h>
#include <midas.h>
main(int argc, char *argv[])
{
  INT  status, i;
  char host_name[256],exp_name[32];

  // get default values from environment
  cm_get_environment(host_name, exp_name);

  // parse command line parameters
  for (i=1 ; i<argc ; i++)
    {
    if (argv[i][0] == '-')
      {
      if (i+1 >= argc || argv[i+1][0] == '-')
        goto usage;
      if (argv[i][1] == 'e')
        strcpy(exp_name, argv[++i]);
      else if (argv[i][1] == 'h')
        strcpy(host_name, argv[++i]);
      else
        {
usage:
        printf("usage: test [-h Hostname] [-e Experiment]\n\n");
        return 1;
        }
      }
    }
  status = cm_connect_experiment(host_name, exp_name, "Test", NULL);
  if (status != CM_SUCCESS)
    return 1;
  ...do operations...
  cm_disconnect_experiment();
}
Parameters:
host_name Specifies host to connect to. Must be a valid IP host name. The string can be empty ("") if to connect to the local computer.
exp_name Specifies the experiment to connect to. If this string is empty, the number of defined experiments in exptab is checked. If only one experiment is defined, the function automatically connects to this one. If more than one experiment is defined, a list is presented and the user can interactively select one experiment.
client_name Client name of the calling program as it can be seen by others (like the scl command in ODBEdit).
func Callback function to read in a password if security has been enabled. In all command line applications this function is NULL which invokes an internal ss_gets() function to read in a password. In windows environments (MS Windows, X Windows) a function can be supplied to open a dialog box and read in the password. The argument of this function must be the returned password.
Returns:
CM_SUCCESS, CM_UNDEF_EXP, CM_SET_ERROR, RPC_NET_ERROR
CM_VERSION_MISMATCH MIDAS library version different on local and remote computer

Definition at line 1842 of file midas.c.

Referenced by main().

01843 {
01844    INT status;
01845    char str[256];
01846 
01847    status =
01848        cm_connect_experiment1(host_name, exp_name, client_name, func, DEFAULT_ODB_SIZE,
01849                               DEFAULT_WATCHDOG_TIMEOUT);
01850    if (status != CM_SUCCESS) {
01851       cm_get_error(status, str);
01852       puts(str);
01853    }
01854 
01855    return status;
01856 }

INT cm_connect_experiment1 ( const char *  host_name,
const char *  exp_name,
const char *  client_name,
void(*)(char *)  func,
INT  odb_size,
DWORD  watchdog_timeout 
)

Connect to a MIDAS experiment (to the online database) on a specific host.

For internal use only.

Definition at line 1864 of file midas.c.

Referenced by cm_connect_experiment(), and main().

01866 {
01867    INT status, i, semaphore_elog, semaphore_alarm, semaphore_history, semaphore_msg, size;
01868    char local_host_name[HOST_NAME_LENGTH];
01869    char client_name1[NAME_LENGTH];
01870    char password[NAME_LENGTH], str[256], exp_name1[NAME_LENGTH];
01871    HNDLE hDB, hKeyClient;
01872    BOOL call_watchdog;
01873    RUNINFO_STR(runinfo_str);
01874 
01875    if (_hKeyClient)
01876       cm_disconnect_experiment();
01877 
01878    rpc_set_name(client_name);
01879 
01880    /* check for local host */
01881    if (equal_ustring(host_name, "local"))
01882       host_name = NULL;
01883 
01884 #ifdef OS_WINNT
01885    {
01886       WSADATA WSAData;
01887 
01888       /* Start windows sockets */
01889       if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
01890          return RPC_NET_ERROR;
01891    }
01892 #endif
01893 
01894    /* search for experiment name in exptab */
01895    if (exp_name == NULL)
01896       exp_name = "";
01897 
01898    strcpy(exp_name1, exp_name);
01899    if (exp_name1[0] == 0) {
01900       status = cm_select_experiment(host_name, exp_name1);
01901       if (status != CM_SUCCESS)
01902          return status;
01903    }
01904 
01905    /* connect to MIDAS server */
01906    if (host_name && host_name[0]) {
01907       status = rpc_server_connect(host_name, exp_name1);
01908       if (status != RPC_SUCCESS)
01909          return status;
01910 
01911       /* register MIDAS library functions */
01912       status = rpc_register_functions(rpc_get_internal_list(1), NULL);
01913       if (status != RPC_SUCCESS)
01914          return status;
01915    } else {
01916       /* lookup path for *SHM files and save it */
01917       status = cm_scan_experiments();
01918       if (status != CM_SUCCESS)
01919          return status;
01920 
01921       for (i = 0; i < MAX_EXPERIMENT && exptab[i].name[0]; i++)
01922          if (equal_ustring(exp_name1, exptab[i].name))
01923             break;
01924 
01925       /* return if experiment not defined */
01926       if (i == MAX_EXPERIMENT || exptab[i].name[0] == 0) {
01927          /* message should be displayed by application
01928             sprintf(str, "Experiment %s not defined in exptab\r", exp_name1);
01929             cm_msg(MERROR, str);
01930           */
01931          return CM_UNDEF_EXP;
01932       }
01933 
01934       cm_set_path(exptab[i].directory);
01935 
01936       /* create alarm and elog semaphores */
01937       status = ss_semaphore_create("ALARM", &semaphore_alarm);
01938       if (status != SS_CREATED && status != SS_SUCCESS) {
01939          cm_msg(MERROR, "cm_connect_experiment", "Cannot create alarm semaphore");
01940          return status;
01941       }
01942       status = ss_semaphore_create("ELOG", &semaphore_elog);
01943       if (status != SS_CREATED && status != SS_SUCCESS) {
01944          cm_msg(MERROR, "cm_connect_experiment", "Cannot create elog semaphore");
01945          return status;
01946       }
01947       status = ss_semaphore_create("HISTORY", &semaphore_history);
01948       if (status != SS_CREATED && status != SS_SUCCESS) {
01949          cm_msg(MERROR, "cm_connect_experiment", "Cannot create history semaphore");
01950          return status;
01951       }
01952       status = ss_semaphore_create("MSG", &semaphore_msg);
01953       if (status != SS_CREATED && status != SS_SUCCESS) {
01954          cm_msg(MERROR, "cm_connect_experiment", "Cannot create message semaphore");
01955          return status;
01956       }
01957 
01958       cm_set_experiment_semaphore(semaphore_alarm, semaphore_elog, semaphore_history, semaphore_msg);
01959    }
01960 
01961    /* open ODB */
01962    if (odb_size == 0)
01963       odb_size = DEFAULT_ODB_SIZE;
01964 
01965    status = db_open_database("ODB", odb_size, &hDB, client_name);
01966    if (status != DB_SUCCESS && status != DB_CREATED) {
01967       cm_msg(MERROR, "cm_connect_experiment1", "cannot open database");
01968       return status;
01969    }
01970 
01971    /* now setup client info */
01972    gethostname(local_host_name, sizeof(local_host_name));
01973 
01974    /* check watchdog timeout */
01975    if (watchdog_timeout == 0)
01976       watchdog_timeout = DEFAULT_WATCHDOG_TIMEOUT;
01977 
01978    strcpy(client_name1, client_name);
01979    password[0] = 0;
01980    status = cm_set_client_info(hDB, &hKeyClient, local_host_name,
01981                                client_name1, rpc_get_option(0, RPC_OHW_TYPE), password, watchdog_timeout);
01982 
01983    if (status == CM_WRONG_PASSWORD) {
01984       if (func == NULL)
01985          strcpy(str, ss_getpass("Password: "));
01986       else
01987          func(str);
01988 
01989       /* re-open database */
01990       status = db_open_database("ODB", odb_size, &hDB, client_name);
01991       if (status != DB_SUCCESS && status != DB_CREATED) {
01992          cm_msg(MERROR, "cm_connect_experiment1", "cannot open database");
01993          return status;
01994       }
01995 
01996       strcpy(password, ss_crypt(str, "mi"));
01997       status = cm_set_client_info(hDB, &hKeyClient, local_host_name,
01998                                   client_name1, rpc_get_option(0, RPC_OHW_TYPE), password, watchdog_timeout);
01999       if (status != CM_SUCCESS) {
02000          /* disconnect */
02001          if (rpc_is_remote())
02002             rpc_server_disconnect();
02003 
02004          return status;
02005       }
02006    }
02007 
02008    cm_set_experiment_database(hDB, hKeyClient);
02009 
02010    /* set experiment name in ODB */
02011    db_set_value(hDB, 0, "/Experiment/Name", exp_name1, NAME_LENGTH, 1, TID_STRING);
02012 
02013    /* set data dir in ODB */
02014    cm_get_path(str);
02015    size = sizeof(str);
02016    db_get_value(hDB, 0, "/Logger/Data dir", str, &size, TID_STRING, TRUE);
02017 
02018    /* check /runinfo structure */
02019    status = db_check_record(hDB, 0, "/Runinfo", strcomb(runinfo_str), TRUE);
02020    if (status == DB_STRUCT_MISMATCH) {
02021       cm_msg(MERROR, "cm_connect_experiment1", "Aborting on mismatching /Runinfo structure");
02022       cm_disconnect_experiment();
02023       abort();
02024    }
02025 
02026    /* register server to be able to be called by other clients */
02027    status = cm_register_server();
02028    if (status != CM_SUCCESS)
02029       return status;
02030 
02031    /* set watchdog timeout */
02032    cm_get_watchdog_params(&call_watchdog, &watchdog_timeout);
02033    size = sizeof(watchdog_timeout);
02034    sprintf(str, "/Programs/%s/Watchdog Timeout", client_name);
02035    db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT, TRUE);
02036    cm_set_watchdog_params(call_watchdog, watchdog_timeout);
02037 
02038    /* send startup notification */
02039    if (strchr(local_host_name, '.'))
02040       *strchr(local_host_name, '.') = 0;
02041 
02042    /* startup message is not displayed */
02043    _message_print = NULL;
02044 
02045    cm_msg(MINFO, "cm_connect_experiment", "Program %s on host %s started", client_name, local_host_name);
02046 
02047    /* enable system and user messages to stdout as default */
02048    cm_set_msg_print(MT_ALL, MT_ALL, puts);
02049 
02050    /* call cm_check_connect when exiting */
02051    atexit((void (*)(void)) cm_check_connect);
02052 
02053    /* register ctrl-c handler */
02054    ss_ctrlc_handler(cm_ctrlc_handler);
02055 
02056    return CM_SUCCESS;
02057 }

INT cm_delete_client_info ( HNDLE  hDB,
INT  pid 
)

Delete client info from database

Parameters:
hDB Database handle
pid PID of entry to delete, zero for this process.
Returns:
CM_SUCCESS

Definition at line 1362 of file midas.c.

Referenced by cm_check_client(), cm_disconnect_experiment(), and cm_shutdown().

01363 {
01364 #ifdef LOCAL_ROUTINES
01365 
01366    /* only do it if local */
01367    if (!rpc_is_remote()) {
01368       INT status;
01369       HNDLE hKey;
01370       char str[256];
01371 
01372       if (!pid)
01373          pid = ss_getpid();
01374 
01375       /* don't delete info from a closed database */
01376       if (_database_entries == 0)
01377          return CM_SUCCESS;
01378 
01379       /* make operation atomic by locking database */
01380       db_lock_database(hDB);
01381 
01382       sprintf(str, "System/Clients/%0d", pid);
01383       status = db_find_key1(hDB, 0, str, &hKey);
01384       if (status != DB_SUCCESS) {
01385          db_unlock_database(hDB);
01386          return status;
01387       }
01388 
01389       /* unlock client entry and delete it without locking DB */
01390       db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, 2);
01391       db_delete_key1(hDB, hKey, 1, TRUE);
01392 
01393       db_unlock_database(hDB);
01394 
01395       /* touch notify key to inform others */
01396       status = 0;
01397       db_set_value(hDB, 0, "/System/Client Notify", &status, sizeof(status), 1, TID_INT);
01398    }
01399 #endif                          /*LOCAL_ROUTINES */
01400 
01401    return CM_SUCCESS;
01402 }

INT cm_deregister_transition ( INT  transition  ) 

Definition at line 2939 of file midas.c.

02940 {
02941    INT status, i;
02942    HNDLE hDB, hKey, hKeyTrans;
02943    char str[256];
02944 
02945    /* check for valid transition */
02946    if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME) {
02947       cm_msg(MERROR, "cm_deregister_transition", "Invalid transition request \"%d\"", transition);
02948       return CM_INVALID_TRANSITION;
02949    }
02950 
02951    cm_get_experiment_database(&hDB, &hKey);
02952 
02953    /* remove existing transition request */
02954    for (i = 0; i < MAX_TRANSITIONS; i++)
02955       if (_trans_table[i].transition == transition)
02956          break;
02957 
02958    if (i == MAX_TRANSITIONS) {
02959       cm_msg(MERROR, "cm_register_transition",
02960              "Cannot de-register transition registration, request not found");
02961       return CM_INVALID_TRANSITION;
02962    }
02963 
02964    _trans_table[i].transition = 0;
02965    _trans_table[i].func = NULL;
02966    _trans_table[i].sequence_number = 0;
02967 
02968    for (i = 0;; i++)
02969       if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition)
02970          break;
02971 
02972    sprintf(str, "Transition %s", trans_name[i].name);
02973 
02974    /* unlock database */
02975    db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
02976 
02977    /* set value */
02978    status = db_find_key(hDB, hKey, str, &hKeyTrans);
02979    if (hKeyTrans) {
02980       status = db_delete_key(hDB, hKeyTrans, FALSE);
02981       if (status != DB_SUCCESS)
02982          return status;
02983    }
02984 
02985    /* re-lock database */
02986    db_set_mode(hDB, hKey, MODE_READ, TRUE);
02987 
02988    return CM_SUCCESS;
02989 }

INT cm_disconnect_client ( HNDLE  hConn,
BOOL  bShutdown 
)

Disconnect from a MIDAS client

Parameters:
hConn Connection handle obtained via cm_connect_client()
bShutdown If TRUE, disconnect from client and shut it down (exit the client program) by sending a RPC_SHUTDOWN message
Returns:
see rpc_client_disconnect()

Definition at line 2286 of file midas.c.

Referenced by command_loop(), do_jrpc_rev0(), interprete(), and show_cnaf_page().

02287 {
02288    return rpc_client_disconnect(hConn, bShutdown);
02289 }

INT cm_disconnect_experiment ( void   ) 

Disconnect from a MIDAS experiment.

Attention:
Should be the last call to a MIDAS library function in an application before it exits. This function removes the client information from the ODB, disconnects all TCP connections and frees all internal allocated memory. See cm_connect_experiment() for example.
Returns:
CM_SUCCESS

Definition at line 2300 of file midas.c.

Referenced by cm_connect_experiment1(), cmd_idle(), ctrlc_odbedit(), main(), register_equipment(), server_loop(), show_status_page(), and usage().

02301 {
02302    HNDLE hDB, hKey;
02303    char local_host_name[HOST_NAME_LENGTH], client_name[80];
02304 
02305    /* send shutdown notification */
02306    rpc_get_name(client_name);
02307    gethostname(local_host_name, sizeof(local_host_name));
02308    if (strchr(local_host_name, '.'))
02309       *strchr(local_host_name, '.') = 0;
02310 
02311    /* disconnect message not displayed */
02312    _message_print = NULL;
02313 
02314    cm_msg(MINFO, "cm_disconnect_experiment", "Program %s on host %s stopped", client_name, local_host_name);
02315 
02316    if (rpc_is_remote()) {
02317       /* close open records */
02318       db_close_all_records();
02319 
02320       rpc_client_disconnect(-1, FALSE);
02321       rpc_server_disconnect();
02322    } else {
02323       rpc_client_disconnect(-1, FALSE);
02324 
02325 #ifdef LOCAL_ROUTINES
02326       ss_alarm(0, cm_watchdog);
02327       _watchdog_last_called = 0;
02328 #endif                          /* LOCAL_ROUTINES */
02329 
02330       /* delete client info */
02331       cm_get_experiment_database(&hDB, &hKey);
02332 
02333       if (hDB)
02334          cm_delete_client_info(hDB, 0);
02335 
02336       bm_close_all_buffers();
02337       db_close_all_databases();
02338    }
02339 
02340    if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_REMOTE)
02341       rpc_server_shutdown();
02342 
02343    /* free RPC list */
02344    rpc_deregister_functions();
02345 
02346    cm_set_experiment_database(0, 0);
02347 
02348    _msg_buffer = 0;
02349 
02350    /* free memory buffers */
02351    if (_event_buffer_size > 0) {
02352       M_FREE(_event_buffer);
02353       _event_buffer_size = 0;
02354    }
02355 
02356    if (_net_recv_buffer_size > 0) {
02357       M_FREE(_net_recv_buffer);
02358       _net_recv_buffer_size = 0;
02359       _net_recv_buffer_size_odb = 0;
02360    }
02361 
02362    if (_net_send_buffer_size > 0) {
02363       M_FREE(_net_send_buffer);
02364       _net_send_buffer_size = 0;
02365    }
02366 
02367    if (_tcp_buffer != NULL) {
02368       M_FREE(_tcp_buffer);
02369       _tcp_buffer = NULL;
02370    }
02371 
02372    return CM_SUCCESS;
02373 }

INT cm_execute ( const char *  command,
char *  result,
INT  bufsize 
)

Executes command via system() call

Parameters:
command Command string to execute
result stdout of command
bufsize string size in byte
Returns:
CM_SUCCESS

Definition at line 4032 of file midas.c.

Referenced by command_loop(), and rpc_server_dispatch().

04033 {
04034    char str[256];
04035    INT n;
04036    int fh;
04037 
04038    if (rpc_is_remote())
04039       return rpc_call(RPC_CM_EXECUTE, command, result, bufsize);
04040 
04041    if (bufsize > 0) {
04042       strcpy(str, command);
04043       sprintf(str, "%s > %d.tmp", command, ss_getpid());
04044 
04045       system(str);
04046 
04047       sprintf(str, "%d.tmp", ss_getpid());
04048       fh = open(str, O_RDONLY, 0644);
04049       result[0] = 0;
04050       if (fh) {
04051          n = read(fh, result, bufsize - 1);
04052          result[MAX(0, n)] = 0;
04053          close(fh);
04054       }
04055       remove(str);
04056    } else
04057       system(command);
04058 
04059    return CM_SUCCESS;
04060 }

INT cm_exist ( const char *  name,
BOOL  bUnique 
)

Check if a MIDAS client exists in current experiment

Parameters:
name Client name
bUnique If true, look for the exact client name. If false, look for namexxx where xxx is a any number
Returns:
CM_SUCCESS, CM_NO_CLIENT

Definition at line 4955 of file midas.c.

Referenced by al_check(), interprete(), main(), rpc_server_dispatch(), show_programs_page(), and show_status_page().

04956 {
04957    INT status, i, size;
04958    HNDLE hDB, hKeyClient, hKey, hSubkey;
04959    char client_name[NAME_LENGTH];
04960 
04961    if (rpc_is_remote())
04962       return rpc_call(RPC_CM_EXIST, name, bUnique);
04963 
04964    cm_get_experiment_database(&hDB, &hKeyClient);
04965 
04966    status = db_find_key(hDB, 0, "System/Clients", &hKey);
04967    if (status != DB_SUCCESS)
04968       return DB_NO_KEY;
04969 
04970    /* loop over all clients */
04971    for (i = 0;; i++) {
04972       status = db_enum_key(hDB, hKey, i, &hSubkey);
04973       if (status == DB_NO_MORE_SUBKEYS)
04974          break;
04975 
04976       if (hSubkey == hKeyClient)
04977          continue;
04978 
04979       if (status == DB_SUCCESS) {
04980          /* get client name */
04981          size = sizeof(client_name);
04982          db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE);
04983 
04984          if (equal_ustring(client_name, name))
04985             return CM_SUCCESS;
04986 
04987          if (!bUnique) {
04988             client_name[strlen(name)] = 0;      /* strip number */
04989             if (equal_ustring(client_name, name))
04990                return CM_SUCCESS;
04991          }
04992       }
04993    }
04994 
04995    return CM_NO_CLIENT;
04996 }

INT cm_get_client_info ( char *  client_name  ) 

Get info about the current client

Parameters:
*client_name Client name.
Returns:
CM_SUCCESS, CM_UNDEF_EXP

Definition at line 1669 of file midas.c.

Referenced by bm_open_buffer(), and debug_print().

01670 {
01671    INT status, length;
01672    HNDLE hDB, hKey;
01673 
01674    /* get root key of client */
01675    cm_get_experiment_database(&hDB, &hKey);
01676    if (!hDB) {
01677       client_name[0] = 0;
01678       return CM_UNDEF_EXP;
01679    }
01680 
01681    status = db_find_key(hDB, hKey, "Name", &hKey);
01682    if (status != DB_SUCCESS)
01683       return status;
01684 
01685    length = NAME_LENGTH;
01686    status = db_get_data(hDB, hKey, client_name, &length, TID_STRING);
01687    if (status != DB_SUCCESS)
01688       return status;
01689 
01690    return CM_SUCCESS;
01691 }

INT cm_get_environment ( char *  host_name,
int  host_name_size,
char *  exp_name,
int  exp_name_size 
)

Returns MIDAS environment variables.

Attention:
This function can be used to evaluate the standard MIDAS environment variables before connecting to an experiment (see Environment variables). The usual way is that the host name and experiment name are first derived from the environment variables MIDAS_SERVER_HOST and MIDAS_EXPT_NAME. They can then be superseded by command line parameters with -h and -e flags.
#include <stdio.h>
#include <midas.h>
main(int argc, char *argv[])
{
  INT  status, i;
  char host_name[256],exp_name[32];

  // get default values from environment
  cm_get_environment(host_name, exp_name);

  // parse command line parameters
  for (i=1 ; i<argc ; i++)
    {
    if (argv[i][0] == '-')
      {
      if (i+1 >= argc || argv[i+1][0] == '-')
        goto usage;
      if (argv[i][1] == 'e')
        strcpy(exp_name, argv[++i]);
      else if (argv[i][1] == 'h')
        strcpy(host_name, argv[++i]);
      else
        {
usage:
        printf("usage: test [-h Hostname] [-e Experiment]\n\n");
        return 1;
        }
      }
    }
  status = cm_connect_experiment(host_name, exp_name, "Test", NULL);
  if (status != CM_SUCCESS)
    return 1;
    ...do anyting...
  cm_disconnect_experiment();
}
Parameters:
host_name Contents of MIDAS_SERVER_HOST environment variable.
host_name_size string length
exp_name Contents of MIDAS_EXPT_NAME environment variable.
exp_name_size string length
Returns:
CM_SUCCESS

Definition at line 1745 of file midas.c.

Referenced by main().

01746 {
01747    host_name[0] = exp_name[0] = 0;
01748 
01749    if (getenv("MIDAS_SERVER_HOST"))
01750       strlcpy(host_name, getenv("MIDAS_SERVER_HOST"), host_name_size);
01751 
01752    if (getenv("MIDAS_EXPT_NAME"))
01753       strlcpy(exp_name, getenv("MIDAS_EXPT_NAME"), exp_name_size);
01754 
01755    return CM_SUCCESS;
01756 }

INT cm_get_experiment_database ( HNDLE *  hDB,
HNDLE *  hKeyClient 
)

Get the handle to the ODB from the currently connected experiment.

Attention:
This function returns the handle of the online database (ODB) which can be used in future db_xxx() calls. The hkeyclient key handle can be used to access the client information in the ODB. If the client key handle is not needed, the parameter can be NULL.
HNDLE hDB, hkeyclient;
 char  name[32];
 int   size;
 db_get_experiment_database(&hdb, &hkeyclient);
 size = sizeof(name);
 db_get_value(hdb, hkeyclient, "Name", name, &size, TID_STRING, TRUE);
 printf("My name is %s\n", name);
Parameters:
hDB Database handle.
hKeyClient Handle for key where search starts, zero for root.
Returns:
CM_SUCCESS

Definition at line 2449 of file midas.c.

Referenced by add_data_dir(), al_check(), al_reset_alarm(), al_trigger_alarm(), ana_end_of_run(), analyzer_init(), assemble_prompt(), bm_open_buffer(), check_web_password(), cm_connect_client(), cm_deregister_transition(), cm_disconnect_experiment(), cm_exist(), cm_get_client_info(), cm_msg_log(), cm_msg_log1(), cm_msg_retrieve(), cm_register_deferred_transition(), cm_register_transition(), cm_set_transition_sequence(), cm_set_watchdog_params(), cm_shutdown(), cm_transition1(), cmd_dir(), command_loop(), do_jrpc_rev0(), el_submit(), evaluate_src(), exec_script(), export_hist(), frontend_init(), gen_odb_attachment(), generate_hist_graph(), get_elog_url(), get_event_id(), get_variable_id(), get_variable_id_tags(), MidasHistory::GetEventsFromEquipment(), MidasHistory::GetEventsFromOdbEvents(), MidasHistory::GetEventsFromOdbTags(), MidasHistory::GetTagsFromEquipment(), MidasHistory::GetTagsFromOdb(), MidasHistory::hs_connect(), MidasHistory::hs_get_events(), interprete(), is_editable(), main(), set_history_path(), show_alarm_page(), show_cnaf_page(), show_config_page(), show_create_page(), show_custom_gif(), show_custom_page(), show_delete_page(), show_elog_delete(), show_elog_new(), show_elog_page(), show_elog_query(), show_elog_submit_query(), show_find_page(), show_form_query(), show_hist_config_page(), show_hist_page(), show_messages_page(), show_odb_page(), show_odb_tag(), show_programs_page(), show_query_page(), show_rawfile(), show_sc_page(), show_set_page(), show_start_page(), show_status_page(), submit_elog(), and submit_form().

02450 {
02451    if (_hDB) {
02452       if (hDB != NULL)
02453          *hDB = _hDB;
02454       if (hKeyClient != NULL)
02455          *hKeyClient = _hKeyClient;
02456    } else {
02457       if (hDB != NULL)
02458          *hDB = rpc_get_server_option(RPC_ODB_HANDLE);
02459       if (hKeyClient != NULL)
02460          *hKeyClient = rpc_get_server_option(RPC_CLIENT_HANDLE);
02461    }
02462 
02463    return CM_SUCCESS;
02464 }

INT cm_get_path ( char *  path  ) 

Return the path name previously set with cm_set_path.

Parameters:
path Pathname
Returns:
CM_SUCCESS

Definition at line 1233 of file midas.c.

Referenced by cm_connect_experiment1(), cm_msg_log(), cm_msg_log1(), cm_msg_retrieve(), command_loop(), list_filename(), and logger_init().

01234 {
01235    strcpy(path, _path_name);
01236 
01237    return CM_SUCCESS;
01238 }

int cm_get_revision (  ) 

Return svn revision number of current MIDAS library as a string

Returns:
revision number

Definition at line 1202 of file midas.c.

Referenced by command_loop().

01203 {
01204    return atoi(svn_revision + 6);
01205 }

char* cm_get_version (  ) 

Return version number of current MIDAS library as a string

Returns:
version number

Definition at line 1193 of file midas.c.

Referenced by command_loop().

01194 {
01195    return MIDAS_VERSION;
01196 }

INT cm_get_watchdog_info ( HNDLE  hDB,
char *  client_name,
DWORD timeout,
DWORD last 
)

Return watchdog information about specific client

Parameters:
hDB ODB handle
client_name ODB client name
timeout Timeout for this application in seconds
last Last time watchdog was called in msec
Returns:
CM_SUCCESS, CM_NO_CLIENT, DB_INVALID_HANDLE

Definition at line 2715 of file midas.c.

Referenced by command_loop(), and rpc_server_dispatch().

02716 {
02717    if (rpc_is_remote())
02718       return rpc_call(RPC_CM_GET_WATCHDOG_INFO, hDB, client_name, timeout, last);
02719 
02720 #ifdef LOCAL_ROUTINES
02721    {
02722       DATABASE_HEADER *pheader;
02723       DATABASE_CLIENT *pclient;
02724       INT i;
02725 
02726       if (hDB > _database_entries || hDB <= 0) {
02727          cm_msg(MERROR, "cm_get_watchdog_info", "invalid database handle");
02728          return DB_INVALID_HANDLE;
02729       }
02730 
02731       if (!_database[hDB - 1].attached) {
02732          cm_msg(MERROR, "cm_get_watchdog_info", "invalid database handle");
02733          return DB_INVALID_HANDLE;
02734       }
02735 
02736       /* lock database */
02737       db_lock_database(hDB);
02738 
02739       pheader = _database[hDB - 1].database_header;
02740       pclient = pheader->client;
02741 
02742       /* find client */
02743       for (i = 0; i < pheader->max_client_index; i++, pclient++)
02744          if (pclient->pid && equal_ustring(pclient->name, client_name)) {
02745             *timeout = pclient->watchdog_timeout;
02746             *last = ss_millitime() - pclient->last_activity;
02747             db_unlock_database(hDB);
02748             return CM_SUCCESS;
02749          }
02750 
02751       *timeout = *last = 0;
02752 
02753       db_unlock_database(hDB);
02754 
02755       return CM_NO_CLIENT;
02756    }
02757 #else                           /* LOCAL_ROUTINES */
02758    return CM_SUCCESS;
02759 #endif                          /* LOCAL_ROUTINES */
02760 }

INT cm_get_watchdog_params ( BOOL call_watchdog,
DWORD timeout 
)

Return the current watchdog parameters

Parameters:
call_watchdog Call the cm_watchdog routine periodically
timeout Timeout for this application in seconds
Returns:
CM_SUCCESS

Definition at line 2695 of file midas.c.

Referenced by bm_open_buffer(), cm_connect_experiment1(), cm_set_client_info(), db_open_database(), lazy_copy(), lazy_main(), log_callback(), and log_write().

02696 {
02697    if (call_watchdog)
02698       *call_watchdog = _call_watchdog;
02699    if (timeout)
02700       *timeout = _watchdog_timeout;
02701 
02702    return CM_SUCCESS;
02703 }

INT cm_list_experiments ( const char *  host_name,
char  exp_name[MAX_EXPERIMENT][NAME_LENGTH] 
)

Connect to a MIDAS server and return all defined experiments in *exp_name[MAX_EXPERIMENTS]

Parameters:
host_name Internet host name.
exp_name list of experiment names
Returns:
CM_SUCCESS, RPC_NET_ERROR

Definition at line 2067 of file midas.c.

Referenced by cm_select_experiment().

02068 {
02069    INT i, status;
02070    struct sockaddr_in bind_addr;
02071    INT sock;
02072    char str[MAX_EXPERIMENT * NAME_LENGTH];
02073    struct hostent *phe;
02074    int port = MIDAS_TCP_PORT;
02075    char hname[256];
02076    char *s;
02077 
02078    if (host_name == NULL || host_name[0] == 0 || equal_ustring(host_name, "local")) {
02079       status = cm_scan_experiments();
02080       if (status != CM_SUCCESS)
02081          return status;
02082 
02083       for (i = 0; i < MAX_EXPERIMENT; i++)
02084          strcpy(exp_name[i], exptab[i].name);
02085 
02086       return CM_SUCCESS;
02087    }
02088 #ifdef OS_WINNT
02089    {
02090       WSADATA WSAData;
02091 
02092       /* Start windows sockets */
02093       if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
02094          return RPC_NET_ERROR;
02095    }
02096 #endif
02097 
02098    /* create a new socket for connecting to remote server */
02099    sock = socket(AF_INET, SOCK_STREAM, 0);
02100    if (sock == -1) {
02101       cm_msg(MERROR, "cm_list_experiments", "cannot create socket");
02102       return RPC_NET_ERROR;
02103    }
02104 
02105    /* extract port number from host_name */
02106    strlcpy(hname, host_name, sizeof(hname));
02107    s = strchr(hname, ':');
02108    if (s) {
02109       *s = 0;
02110       port = strtoul(s + 1, NULL, 0);
02111    }
02112 
02113    /* connect to remote node */
02114    memset(&bind_addr, 0, sizeof(bind_addr));
02115    bind_addr.sin_family = AF_INET;
02116    bind_addr.sin_addr.s_addr = 0;
02117    bind_addr.sin_port = htons(port);
02118 
02119 #ifdef OS_VXWORKS
02120    {
02121       INT host_addr;
02122 
02123       host_addr = hostGetByName(hname);
02124       memcpy((char *) &(bind_addr.sin_addr), &host_addr, 4);
02125    }
02126 #else
02127    phe = gethostbyname(hname);
02128    if (phe == NULL) {
02129       cm_msg(MERROR, "cm_list_experiments", "cannot resolve host name \'%s\'", hname);
02130       return RPC_NET_ERROR;
02131    }
02132    memcpy((char *) &(bind_addr.sin_addr), phe->h_addr, phe->h_length);
02133 #endif
02134 
02135 #ifdef OS_UNIX
02136    do {
02137       status = connect(sock, (void *) &bind_addr, sizeof(bind_addr));
02138 
02139       /* don't return if an alarm signal was cought */
02140    } while (status == -1 && errno == EINTR);
02141 #else
02142    status = connect(sock, (struct sockaddr *) &bind_addr, sizeof(bind_addr));
02143 #endif
02144 
02145    if (status != 0) {
02146 /*    cm_msg(MERROR, "cannot connect"); message should be displayed by application */
02147       return RPC_NET_ERROR;
02148    }
02149 
02150    /* request experiment list */
02151    send(sock, "I", 2, 0);
02152 
02153    for (i = 0; i < MAX_EXPERIMENT; i++) {
02154       exp_name[i][0] = 0;
02155       status = recv_string(sock, str, sizeof(str), _rpc_connect_timeout);
02156 
02157       if (status < 0)
02158          return RPC_NET_ERROR;
02159 
02160       if (status == 0)
02161          break;
02162 
02163       strcpy(exp_name[i], str);
02164    }
02165 
02166    exp_name[i][0] = 0;
02167    closesocket(sock);
02168 
02169    return CM_SUCCESS;
02170 }

INT cm_register_deferred_transition ( INT  transition,
BOOL(*)(INT, BOOL func 
)

Register a deferred transition handler. If a client is registered as a deferred transition handler, it may defer a requested transition by returning FALSE until a certain condition (like a motor reaches its end position) is reached.

Parameters:
transition One of TR_xxx
(*func) Function which gets called whenever a transition is requested. If it returns FALSE, the transition is not performed.
Returns:
CM_SUCCESS, <error> Error from ODB access

Definition at line 3062 of file midas.c.

03063 {
03064    INT status, i, size;
03065    char tr_key_name[256];
03066    HNDLE hDB, hKey;
03067 
03068    cm_get_experiment_database(&hDB, &hKey);
03069 
03070    for (i = 0; _deferred_trans_table[i].transition; i++)
03071       if (_deferred_trans_table[i].transition == transition)
03072          _deferred_trans_table[i].func = (int (*)(int, char *)) func;
03073 
03074    /* set new transition mask */
03075    _deferred_transition_mask |= transition;
03076 
03077    for (i = 0;; i++)
03078       if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition)
03079          break;
03080 
03081    sprintf(tr_key_name, "Transition %s DEFERRED", trans_name[i].name);
03082 
03083    /* unlock database */
03084    db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE, TRUE);
03085 
03086    /* set value */
03087    i = 0;
03088    status = db_set_value(hDB, hKey, tr_key_name, &i, sizeof(INT), 1, TID_INT);
03089    if (status != DB_SUCCESS)
03090       return status;
03091 
03092    /* re-lock database */
03093    db_set_mode(hDB, hKey, MODE_READ, TRUE);
03094 
03095    /* hot link requested transition */
03096    size = sizeof(_requested_transition);
03097    db_get_value(hDB, 0, "/Runinfo/Requested Transition", &_requested_transition, &size, TID_INT, TRUE);
03098    db_find_key(hDB, 0, "/Runinfo/Requested Transition", &hKey);
03099    status = db_open_record(hDB, hKey, &_requested_transition, sizeof(INT), MODE_READ, NULL, NULL);
03100    if (status != DB_SUCCESS) {
03101       cm_msg(MERROR, "cm_register_deferred_transition", "Cannot hotlink /Runinfo/Requested Transition");
03102       return status;
03103    }
03104 
03105    return CM_SUCCESS;
03106 }

INT cm_register_transition ( INT  transition,
INT(*)(INT, char *)  func,
INT  sequence_number 
)

Registers a callback function for run transitions. This function internally registers the transition callback function and publishes its request for transition notification by writing a transition request to /System/Clients/<pid>/Transition XXX. Other clients making a transition scan the transition requests of all clients and call their transition callbacks via RPC.

Clients can register for transitions (Start/Stop/Pause/Resume) in a given sequence. All sequence numbers given in the registration are sorted on a transition and the clients are contacted in ascending order. By default, all programs register with a sequence number of 500. The logger however uses 200 for start, so that it can open files before the other clients are contacted, and 800 for stop, so that the files get closed when all other clients have gone already through the stop trantition.

The callback function returns CM_SUCCESS if it can perform the transition or a value larger than one in case of error. An error string can be copied into the error variable.

Attention:
The callback function will be called on transitions from inside the cm_yield() function which therefore must be contained in the main program loop.
INT start(INT run_number, char *error)
{
  if (<not ok>)
    {
    strcpy(error, "Cannot start because ...");
    return 2;
    }
  printf("Starting run %d\n", run_number);
  return CM_SUCCESS;
}
main()
{
  ...
  cm_register_transition(TR_START, start, 500);
  do
    {
    status = cm_yield(1000);
    } while (status != RPC_SHUTDOWN &&
             status != SS_ABORT);
  ...
}
Parameters:
transition Transition to register for (see State Codes & Transition Codes)
func Callback function.
sequence_number Sequence number for that transition (1..1000)
Returns:
CM_SUCCESS

Definition at line 2874 of file midas.c.

Referenced by main().

02875 {
02876    INT status, i;
02877    HNDLE hDB, hKey, hKeyTrans;
02878    KEY key;
02879    char str[256];
02880 
02881    /* check for valid transition */
02882    if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME
02883        && transition != TR_STARTABORT) {
02884       cm_msg(MERROR, "cm_register_transition", "Invalid transition request \"%d\"", transition);
02885       return CM_INVALID_TRANSITION;
02886    }
02887 
02888    cm_get_experiment_database(&hDB, &hKey);
02889 
02890    rpc_register_function(RPC_RC_TRANSITION, rpc_transition_dispatch);
02891 
02892    /* register new transition request */
02893 
02894    /* find empty slot */
02895    for (i = 0; i < MAX_TRANSITIONS; i++)
02896       if (!_trans_table[i].transition)
02897          break;
02898 
02899    if (i == MAX_TRANSITIONS) {
02900       cm_msg(MERROR, "cm_register_transition",
02901              "To many transition registrations. Please increase MAX_TRANSITIONS and recompile");
02902       return CM_TOO_MANY_REQUESTS;
02903    }
02904 
02905    _trans_table[i].transition = transition;
02906    _trans_table[i].func = func;
02907    _trans_table[i].sequence_number = sequence_number;
02908 
02909    for (i = 0;; i++)
02910       if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition)
02911          break;
02912 
02913    sprintf(str, "Transition %s", trans_name[i].name);
02914 
02915    /* unlock database */
02916    db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
02917 
02918    /* set value */
02919    status = db_find_key(hDB, hKey, str, &hKeyTrans);
02920    if (!hKeyTrans) {
02921       status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT);
02922       if (status != DB_SUCCESS)
02923          return status;
02924    } else {
02925       status = db_get_key(hDB, hKeyTrans, &key);
02926       if (status != DB_SUCCESS)
02927          return status;
02928       status = db_set_data_index(hDB, hKeyTrans, &sequence_number, sizeof(INT), key.num_values, TID_INT);
02929       if (status != DB_SUCCESS)
02930          return status;
02931    }
02932 
02933    /* re-lock database */
02934    db_set_mode(hDB, hKey, MODE_READ, TRUE);
02935 
02936    return CM_SUCCESS;
02937 }

INT cm_scan_experiments ( void   ) 

Scan the "exptab" file for MIDAS experiment names and save them for later use by rpc_server_accept(). The file is first searched under $MIDAS/exptab if present, then the directory from argv[0] is probed.

Returns:
CM_SUCCESS
CM_UNDEF_EXP exptab not found and MIDAS_DIR not set

Definition at line 1269 of file midas.c.

Referenced by cm_connect_experiment1(), and cm_list_experiments().

01270 {
01271    INT i;
01272    FILE *f;
01273    char str[MAX_STRING_LENGTH], alt_str[MAX_STRING_LENGTH], *pdir;
01274 
01275    for (i = 0; i < MAX_EXPERIMENT; i++)
01276       exptab[i].name[0] = 0;
01277 
01278    /* MIDAS_DIR overrides exptab */
01279    if (getenv("MIDAS_DIR")) {
01280       strlcpy(str, getenv("MIDAS_DIR"), sizeof(str));
01281 
01282       strcpy(exptab[0].name, "Default");
01283       strlcpy(exptab[0].directory, getenv("MIDAS_DIR"), sizeof(exptab[0].directory));
01284       exptab[0].user[0] = 0;
01285 
01286       return CM_SUCCESS;
01287    }
01288 
01289    /* default directory for different OSes */
01290 #if defined (OS_WINNT)
01291    if (getenv("SystemRoot"))
01292       strlcpy(str, getenv("SystemRoot"), sizeof(str));
01293    else if (getenv("windir"))
01294       strlcpy(str, getenv("windir"), sizeof(str));
01295    else
01296       strcpy(str, "");
01297 
01298    strcpy(alt_str, str);
01299    strcat(str, "\\system32\\exptab");
01300    strcat(alt_str, "\\system\\exptab");
01301 #elif defined (OS_UNIX)
01302    strcpy(str, "/etc/exptab");
01303    strcpy(alt_str, "/exptab");
01304 #else
01305    strcpy(str, "exptab");
01306    strcpy(alt_str, "exptab");
01307 #endif
01308 
01309    /* MIDAS_EXPTAB overrides default directory */
01310    if (getenv("MIDAS_EXPTAB")) {
01311       strlcpy(str, getenv("MIDAS_EXPTAB"), sizeof(str));
01312       strlcpy(alt_str, getenv("MIDAS_EXPTAB"), sizeof(alt_str));
01313    }
01314 
01315    /* read list of available experiments */
01316    f = fopen(str, "r");
01317    if (f == NULL) {
01318       f = fopen(alt_str, "r");
01319       if (f == NULL)
01320          return CM_UNDEF_ENVIRON;
01321    }
01322 
01323    i = 0;
01324    if (f != NULL) {
01325       do {
01326          str[0] = 0;
01327          if (fgets(str, 100, f) == NULL)
01328             break;
01329          if (str[0] && str[0] != '#' && str[0] != ' ' && str[0] != '\t'
01330              && (strchr(str, ' ') || strchr(str, '\t'))) {
01331             sscanf(str, "%s %s %s", exptab[i].name, exptab[i].directory, exptab[i].user);
01332 
01333             /* check for trailing directory separator */
01334             pdir = exptab[i].directory;
01335             if (pdir[strlen(pdir) - 1] != DIR_SEPARATOR)
01336                strcat(pdir, DIR_SEPARATOR_STR);
01337 
01338             i++;
01339          }
01340       } while (!feof(f));
01341       fclose(f);
01342    }
01343 
01344    /*
01345       for (j=0 ; j<i ; j++)
01346       {
01347       sprintf(str, "Scanned experiment %s", exptab[j].name);
01348       cm_msg(MINFO, str);
01349       }
01350     */
01351 
01352    return CM_SUCCESS;
01353 }

INT cm_select_experiment ( const char *  host_name,
char *  exp_name 
)

Connect to a MIDAS server and select an experiment from the experiments available on this server

For internal use only.

Parameters:
host_name Internet host name.
exp_name list of experiment names
Returns:
CM_SUCCESS, RPC_NET_ERROR

Definition at line 2181 of file midas.c.

Referenced by cm_connect_experiment1().

02182 {
02183    INT status, i;
02184    char expts[MAX_EXPERIMENT][NAME_LENGTH];
02185    char str[32];
02186 
02187    /* retrieve list of experiments and make selection */
02188    status = cm_list_experiments(host_name, expts);
02189    if (status != CM_SUCCESS)
02190       return status;
02191 
02192    if (expts[1][0]) {
02193       if (host_name[0])
02194          printf("Available experiments on server %s:\n", host_name);
02195       else
02196          printf("Available experiments on local computer:\n");
02197 
02198       for (i = 0; expts[i][0]; i++)
02199          printf("%d : %s\n", i, expts[i]);
02200       printf("Select number: ");
02201       ss_gets(str, 32);
02202       i = atoi(str);
02203       strcpy(exp_name, expts[i]);
02204    } else
02205       strcpy(exp_name, expts[0]);
02206 
02207    return CM_SUCCESS;
02208 }

INT cm_set_client_info ( HNDLE  hDB,
HNDLE *  hKeyClient,
char *  host_name,
char *  client_name,
INT  hw_type,
char *  password,
DWORD  watchdog_timeout 
)

Set client information in online database and return handle

Parameters:
hDB Handle to online database
hKeyClient returned key
host_name server name
client_name Name of this program as it will be seen by other clients.
hw_type Type of byte order
password MIDAS password
watchdog_timeout Default watchdog timeout, can be overwritten by ODB setting /programs/<name>/Watchdog timeout
Returns:
CM_SUCCESS

Definition at line 1497 of file midas.c.

Referenced by cm_connect_experiment1(), and rpc_server_dispatch().

01499 {
01500    if (rpc_is_remote())
01501       return rpc_call(RPC_CM_SET_CLIENT_INFO, hDB, hKeyClient,
01502                       host_name, client_name, hw_type, password, watchdog_timeout);
01503 
01504 #ifdef LOCAL_ROUTINES
01505    {
01506       INT status, pid, data, i, idx, size;
01507       HNDLE hKey, hSubkey;
01508       char str[256], name[NAME_LENGTH], orig_name[NAME_LENGTH], pwd[NAME_LENGTH];
01509       BOOL call_watchdog, allow;
01510       PROGRAM_INFO_STR(program_info_str);
01511 
01512       /* check security if password is present */
01513       status = db_find_key(hDB, 0, "/Experiment/Security/Password", &hKey);
01514       if (hKey) {
01515          /* get password */
01516          size = sizeof(pwd);
01517          db_get_data(hDB, hKey, pwd, &size, TID_STRING);
01518 
01519          /* first check allowed hosts list */
01520          allow = FALSE;
01521          db_find_key(hDB, 0, "/Experiment/Security/Allowed hosts", &hKey);
01522          if (hKey && db_find_key(hDB, hKey, host_name, &hKey) == DB_SUCCESS)
01523             allow = TRUE;
01524 
01525          /* check allowed programs list */
01526          db_find_key(hDB, 0, "/Experiment/Security/Allowed programs", &hKey);
01527          if (hKey && db_find_key(hDB, hKey, client_name, &hKey) == DB_SUCCESS)
01528             allow = TRUE;
01529 
01530          /* now check password */
01531          if (!allow && strcmp(password, pwd) != 0) {
01532             if (password[0])
01533                cm_msg(MINFO, "cm_set_client_info", "Wrong password for host %s", host_name);
01534             db_close_all_databases();
01535             bm_close_all_buffers();
01536             _msg_buffer = 0;
01537             return CM_WRONG_PASSWORD;
01538          }
01539       }
01540 
01541       /* make following operation atomic by locking database */
01542       db_lock_database(hDB);
01543 
01544       /* check if entry with this pid exists already */
01545       pid = ss_getpid();
01546 
01547       sprintf(str, "System/Clients/%0d", pid);
01548       status = db_find_key(hDB, 0, str, &hKey);
01549       if (status == DB_SUCCESS) {
01550          db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
01551          db_delete_key(hDB, hKey, TRUE);
01552       }
01553 
01554       if (strlen(client_name) >= NAME_LENGTH)
01555          client_name[NAME_LENGTH] = 0;
01556 
01557       strcpy(name, client_name);
01558       strcpy(orig_name, client_name);
01559 
01560       /* check if client name already exists */
01561       status = db_find_key(hDB, 0, "System/Clients", &hKey);
01562 
01563       for (idx = 1; status != DB_NO_MORE_SUBKEYS; idx++) {
01564          for (i = 0;; i++) {
01565             status = db_enum_key(hDB, hKey, i, &hSubkey);
01566             if (status == DB_NO_MORE_SUBKEYS)
01567                break;
01568 
01569             if (status == DB_SUCCESS) {
01570                size = sizeof(str);
01571                status = db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, TRUE);
01572             }
01573 
01574             /* check if client is living */
01575             if (cm_check_client(hDB, hSubkey) == CM_NO_CLIENT)
01576                continue;
01577 
01578             if (equal_ustring(str, name)) {
01579                sprintf(name, "%s%d", client_name, idx);
01580                break;
01581             }
01582          }
01583       }
01584 
01585       /* set name */
01586       sprintf(str, "System/Clients/%0d/Name", pid);
01587       status = db_set_value(hDB, 0, str, name, NAME_LENGTH, 1, TID_STRING);
01588       if (status != DB_SUCCESS) {
01589          db_unlock_database(hDB);
01590          cm_msg(MERROR, "cm_set_client_info", "cannot set client name");
01591          return status;
01592       }
01593 
01594       /* copy new client name */
01595       strcpy(client_name, name);
01596       db_set_client_name(hDB, client_name);
01597 
01598       /* set also as rpc name */
01599       rpc_set_name(client_name);
01600 
01601       /* use /system/clients/PID as root */
01602       sprintf(str, "System/Clients/%0d", pid);
01603       db_find_key(hDB, 0, str, &hKey);
01604 
01605       /* set host name */
01606       status = db_set_value(hDB, hKey, "Host", host_name, HOST_NAME_LENGTH, 1, TID_STRING);
01607       if (status != DB_SUCCESS) {
01608          db_unlock_database(hDB);
01609          return status;
01610       }
01611 
01612       /* set computer id */
01613       status = db_set_value(hDB, hKey, "Hardware type", &hw_type, sizeof(hw_type), 1, TID_INT);
01614       if (status != DB_SUCCESS) {
01615          db_unlock_database(hDB);
01616          return status;
01617       }
01618 
01619       /* set server port */
01620       data = 0;
01621       status = db_set_value(hDB, hKey, "Server Port", &data, sizeof(INT), 1, TID_INT);
01622       if (status != DB_SUCCESS) {
01623          db_unlock_database(hDB);
01624          return status;
01625       }
01626 
01627       /* lock client entry */
01628       db_set_mode(hDB, hKey, MODE_READ, TRUE);
01629 
01630       /* get (set) default watchdog timeout */
01631       size = sizeof(watchdog_timeout);
01632       sprintf(str, "/Programs/%s/Watchdog Timeout", orig_name);
01633       db_get_value(hDB, 0, str, &watchdog_timeout, &size, TID_INT, TRUE);
01634 
01635       /* define /programs entry */
01636       sprintf(str, "/Programs/%s", orig_name);
01637       db_create_record(hDB, 0, str, strcomb(program_info_str));
01638 
01639       /* save handle for ODB and client */
01640       rpc_set_server_option(RPC_ODB_HANDLE, hDB);
01641       rpc_set_server_option(RPC_CLIENT_HANDLE, hKey);
01642 
01643       /* save watchdog timeout */
01644       cm_get_watchdog_params(&call_watchdog, NULL);
01645       cm_set_watchdog_params(call_watchdog, watchdog_timeout);
01646       if (call_watchdog)
01647          ss_alarm(WATCHDOG_INTERVAL, cm_watchdog);
01648 
01649       /* end of atomic operations */
01650       db_unlock_database(hDB);
01651 
01652       /* touch notify key to inform others */
01653       data = 0;
01654       db_set_value(hDB, 0, "/System/Client Notify", &data, sizeof(data), 1, TID_INT);
01655 
01656       *hKeyClient = hKey;
01657    }
01658 #endif                          /* LOCAL_ROUTINES */
01659 
01660    return CM_SUCCESS;
01661 }

INT cm_set_experiment_database ( HNDLE  hDB,
HNDLE  hKeyClient 
)

Set the handle to the ODB for the currently connected experiment

Parameters:
hDB Database handle
hKeyClient Key handle of client structure
Returns:
CM_SUCCESS

Definition at line 2382 of file midas.c.

Referenced by cm_connect_experiment1(), and cm_disconnect_experiment().

02383 {
02384    _hDB = hDB;
02385    _hKeyClient = hKeyClient;
02386 
02387    return CM_SUCCESS;
02388 }

INT cm_set_path ( char *  path  ) 

Set path to actual experiment. This function gets called by cm_connect_experiment if the connection is established to a local experiment (not through the TCP/IP server). The path is then used for all shared memory routines.

Parameters:
path Pathname
Returns:
CM_SUCCESS

Definition at line 1216 of file midas.c.

Referenced by cm_connect_experiment1().

01217 {
01218    strcpy(_path_name, path);
01219 
01220    /* check for trailing directory seperator */
01221    if (strlen(_path_name) > 0 && _path_name[strlen(_path_name) - 1] != DIR_SEPARATOR)
01222       strcat(_path_name, DIR_SEPARATOR_STR);
01223 
01224    return CM_SUCCESS;
01225 }

INT cm_set_transition_sequence ( INT  transition,
INT  sequence_number 
)

Change the transition sequence for the calling program.

Parameters:
transition TR_START, TR_PAUSE, TR_RESUME or TR_STOP.
sequence_number New sequence number, should be between 1 and 1000
Returns:
CM_SUCCESS

Definition at line 2998 of file midas.c.

02999 {
03000    INT status, i;
03001    HNDLE hDB, hKey;
03002    char str[256];
03003 
03004    /* check for valid transition */
03005    if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME) {
03006       cm_msg(MERROR, "cm_set_transition_sequence", "Invalid transition request \"%d\"", transition);
03007       return CM_INVALID_TRANSITION;
03008    }
03009 
03010    cm_get_experiment_database(&hDB, &hKey);
03011 
03012    /* Find the transition type from the list */
03013    for (i = 0;; i++)
03014       if (trans_name[i].name[0] == 0 || trans_name[i].transition == transition)
03015          break;
03016    sprintf(str, "Transition %s", trans_name[i].name);
03017 
03018    /* Change local sequence number for this transition type */
03019    for (i = 0; i < MAX_TRANSITIONS; i++)
03020       if (_trans_table[i].transition == transition) {
03021          _trans_table[i].sequence_number = sequence_number;
03022          break;
03023       }
03024 
03025    /* unlock database */
03026    db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE, TRUE);
03027 
03028    /* set value */
03029    status = db_set_value(hDB, hKey, str, &sequence_number, sizeof(INT), 1, TID_INT);
03030    if (status != DB_SUCCESS)
03031       return status;
03032 
03033    /* re-lock database */
03034    db_set_mode(hDB, hKey, MODE_READ, TRUE);
03035 
03036    return CM_SUCCESS;
03037 
03038 }

INT cm_set_watchdog_params ( BOOL  call_watchdog,
DWORD  timeout 
)

Sets the internal watchdog flags and the own timeout. If call_watchdog is TRUE, the cm_watchdog routine is called periodically from the system to show other clients that this application is "alive". On UNIX systems, the alarm() timer is used which is then not available for user purposes.

The timeout specifies the time, after which the calling application should be considered "dead" by other clients. Normally, the cm_watchdog() routines is called periodically. If a client crashes, this does not occur any more. Then other clients can detect this and clear all buffer and database entries of this application so they are not blocked any more. If this application should not checked by others, the timeout can be specified as zero. It might be useful for debugging purposes to do so, because if a debugger comes to a breakpoint and stops the application, the periodic call of cm_watchdog is disabled and the client looks like dead.

If the timeout is not zero, but the watchdog is not called (call_watchdog == FALSE), the user must ensure to call cm_watchdog periodically with a period of WATCHDOG_INTERVAL milliseconds or less.

An application which calles system routines which block the alarm signal for some time, might increase the timeout to the maximum expected blocking time before issuing the calls. One example is the logger doing Exabyte tape IO, which can take up to one minute.

Parameters:
call_watchdog Call the cm_watchdog routine periodically
timeout Timeout for this application in ms
Returns:
CM_SUCCESS

Definition at line 2583 of file midas.c.

Referenced by cm_connect_experiment1(), cm_set_client_info(), lazy_copy(), lazy_main(), log_callback(), log_write(), main(), and rpc_server_dispatch().

02584 {
02585    INT i;
02586 
02587    /* set also local timeout to requested value (needed by cm_enable_watchdog()) */
02588    _watchdog_timeout = timeout;
02589 
02590    if (rpc_is_remote())
02591       return rpc_call(RPC_CM_SET_WATCHDOG_PARAMS, call_watchdog, timeout);
02592 
02593 #ifdef LOCAL_ROUTINES
02594 
02595    if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_REMOTE) {
02596       HNDLE hDB, hKey;
02597 
02598       rpc_set_server_option(RPC_WATCHDOG_TIMEOUT, timeout);
02599 
02600       /* write timeout value to client enty in ODB */
02601       cm_get_experiment_database(&hDB, &hKey);
02602 
02603       if (hDB) {
02604          db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE, TRUE);
02605          db_set_value(hDB, hKey, "Link timeout", &timeout, sizeof(timeout), 1, TID_INT);
02606          db_set_mode(hDB, hKey, MODE_READ, TRUE);
02607       }
02608    } else {
02609       _call_watchdog = call_watchdog;
02610       _watchdog_timeout = timeout;
02611 
02612       /* set watchdog flag of all open buffers */
02613       for (i = _buffer_entries; i > 0; i--) {
02614          BUFFER_CLIENT *pclient;
02615          BUFFER_HEADER *pheader;
02616          INT idx;
02617 
02618          idx = bm_validate_client_index(&_buffer[i - 1]);
02619          pheader = _buffer[i - 1].buffer_header;
02620          pclient = &pheader->client[idx];
02621 
02622          if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE
02623              && _buffer[i - 1].index != rpc_get_server_acception())
02624             continue;
02625 
02626          if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE && _buffer[i - 1].index != ss_gettid())
02627             continue;
02628 
02629          if (!_buffer[i - 1].attached)
02630             continue;
02631 
02632          /* clear entry from client structure in buffer header */
02633          pclient->watchdog_timeout = timeout;
02634 
02635          /* show activity */
02636          pclient->last_activity = ss_millitime();
02637       }
02638 
02639       /* set watchdog flag of alll open databases */
02640       for (i = _database_entries; i > 0; i--) {
02641          DATABASE_HEADER *pheader;
02642          DATABASE_CLIENT *pclient;
02643          INT idx;
02644 
02645          db_lock_database(i);
02646          idx = _database[i - 1].client_index;
02647          pheader = _database[i - 1].database_header;
02648          pclient = &pheader->client[idx];
02649 
02650          if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE &&
02651              _database[i - 1].index != rpc_get_server_acception()) {
02652             db_unlock_database(i);
02653             continue;
02654          }
02655 
02656          if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE && _database[i - 1].index != ss_gettid()) {
02657             db_unlock_database(i);
02658             continue;
02659          }
02660 
02661          if (!_database[i - 1].attached) {
02662             db_unlock_database(i);
02663             continue;
02664          }
02665 
02666          /* clear entry from client structure in buffer header */
02667          pclient->watchdog_timeout = timeout;
02668 
02669          /* show activity */
02670          pclient->last_activity = ss_millitime();
02671 
02672          db_unlock_database(i);
02673       }
02674 
02675       if (call_watchdog)
02676          /* restart watchdog */
02677          ss_alarm(WATCHDOG_INTERVAL, cm_watchdog);
02678       else
02679          /* kill current timer */
02680          ss_alarm(0, cm_watchdog);
02681    }
02682 
02683 #endif                          /* LOCAL_ROUTINES */
02684 
02685    return CM_SUCCESS;
02686 }

INT cm_shutdown ( const char *  name,
BOOL  bUnique 
)

Shutdown (exit) other MIDAS client

Parameters:
name Client name or "all" for all clients
bUnique If true, look for the exact client name. If false, look for namexxx where xxx is a any number.
Returns:
CM_SUCCESS, CM_NO_CLIENT, DB_NO_KEY

Definition at line 4846 of file midas.c.

Referenced by cm_transition1(), command_loop(), main(), and show_programs_page().

04847 {
04848    INT status, return_status, i, size;
04849    HNDLE hDB, hKeyClient, hKey, hSubkey, hKeyTmp, hConn;
04850    KEY key;
04851    char client_name[NAME_LENGTH], remote_host[HOST_NAME_LENGTH];
04852    INT port;
04853    DWORD start_time;
04854 
04855    cm_get_experiment_database(&hDB, &hKeyClient);
04856 
04857    status = db_find_key(hDB, 0, "System/Clients", &hKey);
04858    if (status != DB_SUCCESS)
04859       return DB_NO_KEY;
04860 
04861    return_status = CM_NO_CLIENT;
04862 
04863    /* loop over all clients */
04864    for (i = 0;; i++) {
04865       status = db_enum_key(hDB, hKey, i, &hSubkey);
04866       if (status == DB_NO_MORE_SUBKEYS)
04867          break;
04868 
04869       /* don't shutdown ourselves */
04870       if (hSubkey == hKeyClient)
04871          continue;
04872 
04873       if (status == DB_SUCCESS) {
04874          db_get_key(hDB, hSubkey, &key);
04875 
04876          /* contact client */
04877          size = sizeof(client_name);
04878          db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE);
04879 
04880          if (!bUnique)
04881             client_name[strlen(name)] = 0;      /* strip number */
04882 
04883          /* check if individual client */
04884          if (!equal_ustring("all", name) && !equal_ustring(client_name, name))
04885             continue;
04886 
04887          size = sizeof(port);
04888          db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT, TRUE);
04889 
04890          size = sizeof(remote_host);
04891          db_get_value(hDB, hSubkey, "Host", remote_host, &size, TID_STRING, TRUE);
04892 
04893          /* client found -> connect to its server port */
04894          status = rpc_client_connect(remote_host, port, client_name, &hConn);
04895          if (status != RPC_SUCCESS) {
04896             int client_pid = atoi(key.name);
04897             return_status = CM_NO_CLIENT;
04898             cm_msg(MERROR, "cm_shutdown", "Cannot connect to client \'%s\' on host \'%s\', port %d",
04899                    client_name, remote_host, port);
04900 #ifdef SIGKILL
04901             cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name,
04902                    client_pid);
04903             kill(client_pid, SIGKILL);
04904             status = cm_delete_client_info(hDB, client_pid);
04905             if (status != CM_SUCCESS)
04906                cm_msg(MERROR, "cm_shutdown", "Cannot delete client info for client \'%s\', pid %d, status %d",
04907                       name, client_pid, status);
04908 #endif
04909          } else {
04910             /* call disconnect with shutdown=TRUE */
04911             rpc_client_disconnect(hConn, TRUE);
04912 
04913             /* wait until client has shut down */
04914             start_time = ss_millitime();
04915             do {
04916                ss_sleep(100);
04917                status = db_find_key(hDB, hKey, key.name, &hKeyTmp);
04918             } while (status == DB_SUCCESS && (ss_millitime() - start_time < 5000));
04919 
04920             if (status == DB_SUCCESS) {
04921                int client_pid = atoi(key.name);
04922                return_status = CM_NO_CLIENT;
04923                cm_msg(MERROR, "cm_shutdown", "Client \'%s\' not responding to shutdown command", client_name);
04924 #ifdef SIGKILL
04925                cm_msg(MERROR, "cm_shutdown", "Killing and Deleting client \'%s\' pid %d", client_name,
04926                       client_pid);
04927                kill(client_pid, SIGKILL);
04928                status = cm_delete_client_info(hDB, client_pid);
04929                if (status != CM_SUCCESS)
04930                   cm_msg(MERROR, "cm_shutdown",
04931                          "Cannot delete client info for client \'%s\', pid %d, status %d", name, client_pid,
04932                          status);
04933 #endif
04934                return_status = CM_NO_CLIENT;
04935             } else {
04936                return_status = CM_SUCCESS;
04937                i--;
04938             }
04939          }
04940       }
04941    }
04942 
04943    return return_status;
04944 }

INT cm_synchronize ( DWORD seconds  ) 

Get time from MIDAS server and set local time.

Parameters:
seconds Time in seconds
Returns:
CM_SUCCESS

Definition at line 1107 of file midas.c.

Referenced by main(), and rpc_server_dispatch().

01108 {
01109    INT sec, status;
01110 
01111    /* if connected to server, get time from there */
01112    if (rpc_is_remote()) {
01113       status = rpc_call(RPC_CM_SYNCHRONIZE, &sec);
01114 
01115       /* set local time */
01116       if (status == CM_SUCCESS)
01117          ss_settime(sec);
01118    }
01119 
01120    /* return time to caller */
01121    if (seconds != NULL) {
01122       *seconds = ss_time();
01123    }
01124 
01125    return CM_SUCCESS;
01126 }

INT cm_time ( DWORD t  ) 

Get time from ss_time on server.

Parameters:
t string
Returns:
CM_SUCCESS

Definition at line 1153 of file midas.c.

Referenced by cm_transition1(), and rpc_server_dispatch().

01154 {
01155    /* if connected to server, get time from there */
01156    if (rpc_is_remote())
01157       return rpc_call(RPC_CM_TIME, t);
01158 
01159    /* return local time */
01160    *t = ss_time();
01161 
01162    return CM_SUCCESS;
01163 }

INT cm_transition ( INT  transition,
INT  run_number,
char *  errstr,
INT  errstr_size,
INT  async_flag,
INT  debug_flag 
)

Definition at line 3867 of file midas.c.

Referenced by cm_check_deferred_transition(), command_loop(), interprete(), log_write(), main(), scan_fragment(), start_the_run(), and stop_the_run().

03869 {
03870    int status;
03871 
03872    status = cm_transition1(transition, run_number, errstr, errstr_size, async_flag, debug_flag);
03873 
03874    if (transition == TR_START && status != CM_SUCCESS) {
03875       cm_msg(MERROR, "cm_transition", "Could not start a run: cm_transition() status %d, message \'%s\'",
03876              status, errstr);
03877       cm_transition1(TR_STARTABORT, run_number, NULL, 0, async_flag, debug_flag);
03878    }
03879 
03880    return status;
03881 }

INT cm_transition1 ( INT  transition,
INT  run_number,
char *  errstr,
INT  errstr_size,
INT  async_flag,
INT  debug_flag 
)

Performs a run transition (Start/Stop/Pause/Resume).

Synchronous/Asynchronous flag. If set to ASYNC, the transition is done asynchronously, meaning that clients are connected and told to execute their callback routine, but no result is awaited. The return value is specified by the transition callback function on the remote clients. If all callbacks can perform the transition, CM_SUCCESS is returned. If one callback cannot perform the transition, the return value of this callback is returned from cm_transition(). The async_flag is usually FALSE so that transition callbacks can block a run transition in case of problems and return an error string. The only exception are situations where a run transition is performed automatically by a program which cannot block in a transition. For example the logger can cause a run stop when a disk is nearly full but it cannot block in the cm_transition() function since it has its own run stop callback which must flush buffers and close disk files and tapes.

...
    i = 1;
    db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT);

      status = cm_transition(TR_START, new_run_number, str, sizeof(str), SYNC, debug_flag);
      if (status != CM_SUCCESS)
      {
        // in case of error
        printf("Error: %s\n", str);
      }
    ...
Parameters:
transition TR_START, TR_PAUSE, TR_RESUME or TR_STOP.
run_number New run number. If zero, use current run number plus one.
errstr returned error string.
errstr_size Size of error string.
async_flag SYNC: synchronization flag (SYNC:wait completion, ASYNC: retun immediately)
debug_flag If 1 output debugging information, if 2 output via cm_msg().
Returns:
CM_SUCCESS, <error> error code from remote client

Definition at line 3212 of file midas.c.

Referenced by cm_transition().

03214 {
03215    INT i, j, status, idx, size, sequence_number, port, state, old_timeout, n_tr_clients;
03216    HNDLE hDB, hRootKey, hSubkey, hKey, hKeylocal, hConn, hKeyTrans;
03217    DWORD seconds;
03218    char host_name[HOST_NAME_LENGTH], client_name[NAME_LENGTH], str[256], error[256], tr_key_name[256];
03219    char *trname = "unknown";
03220    KEY key;
03221    BOOL deferred;
03222    PROGRAM_INFO program_info;
03223    TR_CLIENT *tr_client;
03224    int connect_timeout = 10000;
03225    int timeout = 120000;
03226    int t0, t1;
03227 
03228    deferred = (transition & TR_DEFERRED) > 0;
03229    transition &= ~TR_DEFERRED;
03230 
03231    /* check for valid transition */
03232    if (transition != TR_START && transition != TR_STOP && transition != TR_PAUSE && transition != TR_RESUME
03233        && transition != TR_STARTABORT) {
03234       cm_msg(MERROR, "cm_transition", "Invalid transition request \"%d\"", transition);
03235       if (errstr != NULL)
03236          strlcpy(errstr, "Invalid transition request", errstr_size);
03237       return CM_INVALID_TRANSITION;
03238    }
03239 
03240    /* get key of local client */
03241    cm_get_experiment_database(&hDB, &hKeylocal);
03242 
03243    if (errstr != NULL)
03244       strlcpy(errstr, "Unknown error", errstr_size);
03245 
03246    if (debug_flag == 0) {
03247       size = sizeof(i);
03248       db_get_value(hDB, 0, "/Experiment/Transition debug flag", &debug_flag, &size, TID_INT, TRUE);
03249    }
03250 
03251    /* do detached transition via mtransition tool */
03252    if (async_flag == DETACH) {
03253       char *args[100];
03254       int iarg = 0;
03255       char debug_arg[256];
03256       char start_arg[256];
03257       char expt_name[256];
03258       extern RPC_SERVER_CONNECTION _server_connection;
03259 
03260       args[iarg++] = "mtransition";
03261 
03262       if (_server_connection.send_sock) {
03263          /* if connected to mserver, pass connection info to mtransition */
03264          args[iarg++] = "-h";
03265          args[iarg++] = _server_connection.host_name;
03266          args[iarg++] = "-e";
03267          args[iarg++] = _server_connection.exp_name;
03268       } else {
03269          /* get experiment name from ODB */
03270          size = sizeof(expt_name);
03271          db_get_value(hDB, 0, "/Experiment/Name", expt_name, &size, TID_STRING, FALSE);
03272 
03273          args[iarg++] = "-e";
03274          args[iarg++] = expt_name;
03275       }
03276 
03277       if (debug_flag) {
03278          args[iarg++] = "-d";
03279 
03280          sprintf(debug_arg, "%d", debug_flag);
03281          args[iarg++] = debug_arg;
03282       }
03283 
03284       if (transition == TR_STOP)
03285          args[iarg++] = "STOP";
03286       else if (transition == TR_PAUSE)
03287          args[iarg++] = "PAUSE";
03288       else if (transition == TR_RESUME)
03289          args[iarg++] = "RESUME";
03290       else if (transition == TR_START) {
03291          args[iarg++] = "START";
03292 
03293          sprintf(start_arg, "%d", run_number);
03294          args[iarg++] = start_arg;
03295       }
03296 
03297       args[iarg++] = NULL;
03298 
03299       if (0)
03300          for (iarg = 0; args[iarg] != NULL; iarg++)
03301             printf("arg[%d] [%s]\n", iarg, args[iarg]);
03302 
03303       status = ss_spawnv(P_DETACH, args[0], args);
03304 
03305       if (status != SUCCESS) {
03306          if (errstr != NULL)
03307             sprintf(errstr, "Cannot execute mtransition, ss_spawnvp() returned %d", status);
03308          return CM_SET_ERROR;
03309       }
03310 
03311       return CM_SUCCESS;
03312    }
03313 
03314    /* if no run number is given, get it from DB */
03315    if (run_number == 0) {
03316       size = sizeof(run_number);
03317       status = db_get_value(hDB, 0, "Runinfo/Run number", &run_number, &size, TID_INT, TRUE);
03318       assert(status == SUCCESS);
03319    }
03320 
03321    if (run_number <= 0) {
03322       cm_msg(MERROR, "cm_transition", "aborting on attempt to use invalid run number %d", run_number);
03323       abort();
03324    }
03325 
03326    /* check if transition in progress */
03327    if (!deferred) {
03328       i = 0;
03329       size = sizeof(i);
03330       db_get_value(hDB, 0, "/Runinfo/Transition in progress", &i, &size, TID_INT, TRUE);
03331       if (i == 1) {
03332          sprintf(errstr, "Start/Stop transition %d already in progress, please try again later\n", i);
03333          strlcat(errstr, "or set \"/Runinfo/Transition in progress\" manually to zero.\n", errstr_size);
03334          return CM_TRANSITION_IN_PROGRESS;
03335       }
03336    }
03337 
03338    /* get transition timeout for rpc connect */
03339    size = sizeof(timeout);
03340    db_get_value(hDB, 0, "/Experiment/Transition connect timeout", &connect_timeout, &size, TID_INT, TRUE);
03341 
03342    if (connect_timeout < 1000)
03343       connect_timeout = 1000;
03344 
03345    /* get transition timeout */
03346    size = sizeof(timeout);
03347    db_get_value(hDB, 0, "/Experiment/Transition timeout", &timeout, &size, TID_INT, TRUE);
03348 
03349    if (timeout < 1000)
03350       timeout = 1000;
03351 
03352    /* indicate transition in progress */
03353    i = transition;
03354    db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT);
03355 
03356    /* clear run abort flag */
03357    i = 0;
03358    db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT);
03359 
03360    /* Set new run number in ODB */
03361    if (transition == TR_START) {
03362       if (debug_flag == 1)
03363          printf("Setting run number %d in ODB\n", run_number);
03364       if (debug_flag == 2)
03365          cm_msg(MINFO, "cm_transition", "cm_transition: Setting run number %d in ODB", run_number);
03366 
03367       status = db_set_value(hDB, 0, "Runinfo/Run number", &run_number, sizeof(run_number), 1, TID_INT);
03368       assert(status == SUCCESS);
03369       if (status != DB_SUCCESS)
03370          cm_msg(MERROR, "cm_transition", "cannot set Runinfo/Run number in database");
03371    }
03372 
03373    if (deferred) {
03374       /* remove transition request */
03375       i = 0;
03376       db_set_value(hDB, 0, "/Runinfo/Requested transition", &i, sizeof(int), 1, TID_INT);
03377    } else {
03378       status = db_find_key(hDB, 0, "System/Clients", &hRootKey);
03379       if (status != DB_SUCCESS) {
03380          cm_msg(MERROR, "cm_transition", "cannot find System/Clients entry in database");
03381          if (errstr != NULL)
03382             strlcpy(errstr, "Cannot find /System/Clients in ODB", errstr_size);
03383          return status;
03384       }
03385 
03386       /* check if deferred transition already in progress */
03387       size = sizeof(i);
03388       db_get_value(hDB, 0, "/Runinfo/Requested transition", &i, &size, TID_INT, TRUE);
03389       if (i) {
03390          if (errstr != NULL)
03391             strlcpy(errstr, "Deferred transition already in progress", errstr_size);
03392          return CM_TRANSITION_IN_PROGRESS;
03393       }
03394 
03395       for (i = 0; trans_name[i].name[0] != 0; i++)
03396          if (trans_name[i].transition == transition) {
03397             trname = trans_name[i].name;
03398             break;
03399          }
03400 
03401       sprintf(tr_key_name, "Transition %s DEFERRED", trname);
03402 
03403       /* search database for clients with deferred transition request */
03404       for (i = 0, status = 0;; i++) {
03405          status = db_enum_key(hDB, hRootKey, i, &hSubkey);
03406          if (status == DB_NO_MORE_SUBKEYS)
03407             break;
03408 
03409          if (status == DB_SUCCESS) {
03410             size = sizeof(sequence_number);
03411             status = db_get_value(hDB, hSubkey, tr_key_name, &sequence_number, &size, TID_INT, FALSE);
03412 
03413             /* if registered for deferred transition, set flag in ODB and return */
03414             if (status == DB_SUCCESS) {
03415                size = NAME_LENGTH;
03416                db_get_value(hDB, hSubkey, "Name", str, &size, TID_STRING, TRUE);
03417                db_set_value(hDB, 0, "/Runinfo/Requested transition", &transition, sizeof(int), 1, TID_INT);
03418 
03419                if (debug_flag == 1)
03420                   printf("---- Transition %s deferred by client \"%s\" ----\n", trname, str);
03421                if (debug_flag == 2)
03422                   cm_msg(MINFO, "cm_transition",
03423                          "cm_transition: ---- Transition %s deferred by client \"%s\" ----", trname, str);
03424 
03425                if (errstr)
03426                   sprintf(errstr, "Transition %s deferred by client \"%s\"", trname, str);
03427 
03428                return CM_DEFERRED_TRANSITION;
03429             }
03430          }
03431       }
03432    }
03433 
03434    /* execute programs on start */
03435    if (transition == TR_START) {
03436       str[0] = 0;
03437       size = sizeof(str);
03438       db_get_value(hDB, 0, "/Programs/Execute on start run", str, &size, TID_STRING, TRUE);
03439       if (str[0])
03440          ss_system(str);
03441 
03442       db_find_key(hDB, 0, "/Programs", &hRootKey);
03443       if (hRootKey) {
03444          for (i = 0;; i++) {
03445             status = db_enum_key(hDB, hRootKey, i, &hKey);
03446             if (status == DB_NO_MORE_SUBKEYS)
03447                break;
03448 
03449             db_get_key(hDB, hKey, &key);
03450 
03451             /* don't check "execute on xxx" */
03452             if (key.type != TID_KEY)
03453                continue;
03454 
03455             size = sizeof(program_info);
03456             status = db_get_record(hDB, hKey, &program_info, &size, 0);
03457             if (status != DB_SUCCESS) {
03458                cm_msg(MERROR, "cm_transition", "Cannot get program info record");
03459                continue;
03460             }
03461 
03462             if (program_info.auto_start && program_info.start_command[0])
03463                ss_system(program_info.start_command);
03464          }
03465       }
03466    }
03467 
03468    /* set new start time in database */
03469    if (transition == TR_START) {
03470       /* ASCII format */
03471       cm_asctime(str, sizeof(str));
03472       db_set_value(hDB, 0, "Runinfo/Start Time", str, 32, 1, TID_STRING);
03473 
03474       /* reset stop time */
03475       seconds = 0;
03476       db_set_value(hDB, 0, "Runinfo/Stop Time binary", &seconds, sizeof(seconds), 1, TID_DWORD);
03477 
03478       /* Seconds since 1.1.1970 */
03479       cm_time(&seconds);
03480       db_set_value(hDB, 0, "Runinfo/Start Time binary", &seconds, sizeof(seconds), 1, TID_DWORD);
03481    }
03482 
03483    /* set stop time in database */
03484    if (transition == TR_STOP) {
03485       size = sizeof(state);
03486       status = db_get_value(hDB, 0, "Runinfo/State", &state, &size, TID_INT, TRUE);
03487       if (status != DB_SUCCESS)
03488          cm_msg(MERROR, "cm_transition", "cannot get Runinfo/State in database");
03489 
03490       if (state != STATE_STOPPED) {
03491          /* stop time binary */
03492          cm_time(&seconds);
03493          status = db_set_value(hDB, 0, "Runinfo/Stop Time binary", &seconds, sizeof(seconds), 1, TID_DWORD);
03494          if (status != DB_SUCCESS)
03495             cm_msg(MERROR, "cm_transition", "cannot set \"Runinfo/Stop Time binary\" in database");
03496 
03497          /* stop time ascii */
03498          cm_asctime(str, sizeof(str));
03499          status = db_set_value(hDB, 0, "Runinfo/Stop Time", str, 32, 1, TID_STRING);
03500          if (status != DB_SUCCESS)
03501             cm_msg(MERROR, "cm_transition", "cannot set \"Runinfo/Stop Time\" in database");
03502       }
03503    }
03504 
03505    status = db_find_key(hDB, 0, "System/Clients", &hRootKey);
03506    if (status != DB_SUCCESS) {
03507       cm_msg(MERROR, "cm_transition", "cannot find System/Clients entry in database");
03508       if (errstr)
03509          strlcpy(errstr, "Cannot find /System/Clients in ODB", errstr_size);
03510       return status;
03511    }
03512 
03513    for (i = 0; trans_name[i].name[0] != 0; i++)
03514       if (trans_name[i].transition == transition) {
03515          trname = trans_name[i].name;
03516          break;
03517       }
03518 
03519    /* check that all transition clients are alive */
03520    for (i = 0;;) {
03521       status = db_enum_key(hDB, hRootKey, i, &hSubkey);
03522       if (status != DB_SUCCESS)
03523          break;
03524 
03525       status = cm_check_client(hDB, hSubkey);
03526 
03527       if (status == DB_SUCCESS) {
03528          /* this client is alive. Check next one! */
03529          i++;
03530          continue;
03531       }
03532 
03533       assert(status == CM_NO_CLIENT);
03534 
03535       /* start from scratch: removing odb entries as we iterate over them
03536        * does strange things to db_enum_key() */
03537       i = 0;
03538    }
03539 
03540    if (debug_flag == 1)
03541       printf("---- Transition %s started ----\n", trname);
03542    if (debug_flag == 2)
03543       cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s started ----", trname);
03544 
03545    sprintf(tr_key_name, "Transition %s", trname);
03546 
03547    /* search database for clients which registered for transition */
03548    n_tr_clients = 0;
03549    tr_client = NULL;
03550 
03551    for (i = 0, status = 0;; i++) {
03552       status = db_enum_key(hDB, hRootKey, i, &hSubkey);
03553       if (status == DB_NO_MORE_SUBKEYS)
03554          break;
03555 
03556       if (status == DB_SUCCESS) {
03557          status = db_find_key(hDB, hSubkey, tr_key_name, &hKeyTrans);
03558 
03559          if (status == DB_SUCCESS) {
03560 
03561             db_get_key(hDB, hKeyTrans, &key);
03562 
03563             for (j = 0; j < key.num_values; j++) {
03564                size = sizeof(sequence_number);
03565                status = db_get_data_index(hDB, hKeyTrans, &sequence_number, &size, j, TID_INT);
03566                assert(status == DB_SUCCESS);
03567 
03568                if (tr_client == NULL)
03569                   tr_client = (TR_CLIENT *) malloc(sizeof(TR_CLIENT));
03570                else
03571                   tr_client = (TR_CLIENT *) realloc(tr_client, sizeof(TR_CLIENT) * (n_tr_clients + 1));
03572                assert(tr_client);
03573 
03574                tr_client[n_tr_clients].sequence_number = sequence_number;
03575 
03576                if (hSubkey == hKeylocal) {
03577                   /* remember own client */
03578                   tr_client[n_tr_clients].port = 0;
03579                } else {
03580                   /* get client info */
03581                   size = sizeof(client_name);
03582                   db_get_value(hDB, hSubkey, "Name", client_name, &size, TID_STRING, TRUE);
03583                   strcpy(tr_client[n_tr_clients].client_name, client_name);
03584 
03585                   size = sizeof(port);
03586                   db_get_value(hDB, hSubkey, "Server Port", &port, &size, TID_INT, TRUE);
03587                   tr_client[n_tr_clients].port = port;
03588 
03589                   size = sizeof(host_name);
03590                   db_get_value(hDB, hSubkey, "Host", host_name, &size, TID_STRING, TRUE);
03591                   strcpy(tr_client[n_tr_clients].host_name, host_name);
03592                }
03593 
03594                n_tr_clients++;
03595             }
03596          }
03597       }
03598    }
03599 
03600    /* sort clients according to sequence number */
03601    if (n_tr_clients > 1)
03602       qsort(tr_client, n_tr_clients, sizeof(TR_CLIENT), tr_compare);
03603 
03604    /* contact ordered clients for transition */
03605    for (idx = 0; idx < n_tr_clients; idx++) {
03606       /* erase error string */
03607       error[0] = 0;
03608 
03609       if (debug_flag == 1)
03610          printf("\n==== Found client \"%s\" with sequence number %d\n",
03611                 tr_client[idx].client_name, tr_client[idx].sequence_number);
03612       if (debug_flag == 2)
03613          cm_msg(MINFO, "cm_transition",
03614                 "cm_transition: ==== Found client \"%s\" with sequence number %d",
03615                 tr_client[idx].client_name, tr_client[idx].sequence_number);
03616 
03617       /* if own client call transition callback directly */
03618       if (tr_client[idx].port == 0) {
03619          for (i = 0; _trans_table[i].transition; i++)
03620             if (_trans_table[i].transition == transition)
03621                break;
03622 
03623          /* call registered function */
03624          if (_trans_table[i].transition == transition && _trans_table[i].func) {
03625             if (debug_flag == 1)
03626                printf("Calling local transition callback\n");
03627             if (debug_flag == 2)
03628                cm_msg(MINFO, "cm_transition", "cm_transition: Calling local transition callback");
03629 
03630             status = _trans_table[i].func(run_number, error);
03631 
03632             if (debug_flag == 1)
03633                printf("Local transition callback finished\n");
03634             if (debug_flag == 2)
03635                cm_msg(MINFO, "cm_transition", "cm_transition: Local transition callback finished");
03636          } else
03637             status = CM_SUCCESS;
03638 
03639          if (errstr != NULL)
03640             memcpy(errstr, error,
03641                    (INT) strlen(error) + 1 < errstr_size ? (INT) strlen(error) + 1 : errstr_size);
03642 
03643          if (status != CM_SUCCESS) {
03644             /* indicate abort */
03645             i = 1;
03646             db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT);
03647             i = 0;
03648             db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT);
03649 
03650             free(tr_client);
03651             return status;
03652          }
03653 
03654       } else {
03655 
03656          /* contact client if transition mask set */
03657          if (debug_flag == 1)
03658             printf("Connecting to client \"%s\" on host %s...\n", tr_client[idx].client_name,
03659                    tr_client[idx].host_name);
03660          if (debug_flag == 2)
03661             cm_msg(MINFO, "cm_transition",
03662                    "cm_transition: Connecting to client \"%s\" on host %s...",
03663                    tr_client[idx].client_name, tr_client[idx].host_name);
03664 
03665          /* set our timeout for rpc_client_connect() */
03666          old_timeout = rpc_get_option(-2, RPC_OTIMEOUT);
03667          rpc_set_option(-2, RPC_OTIMEOUT, connect_timeout);
03668 
03669          /* client found -> connect to its server port */
03670          status =
03671              rpc_client_connect(tr_client[idx].host_name, tr_client[idx].port, tr_client[idx].client_name,
03672                                 &hConn);
03673 
03674          rpc_set_option(-2, RPC_OTIMEOUT, old_timeout);
03675 
03676          if (status != RPC_SUCCESS) {
03677             cm_msg(MERROR, "cm_transition",
03678                    "cannot connect to client \"%s\" on host %s, port %d, status %d",
03679                    tr_client[idx].client_name, tr_client[idx].host_name, tr_client[idx].port, status);
03680             if (errstr != NULL) {
03681                strlcpy(errstr, "Cannot connect to client \'", errstr_size);
03682                strlcat(errstr, tr_client[idx].client_name, errstr_size);
03683                strlcat(errstr, "\'", errstr_size);
03684             }
03685 
03686             /* clients that do not respond to transitions are dead or defective, get rid of them. K.O. */
03687             cm_shutdown(tr_client[idx].client_name, TRUE);
03688             cm_cleanup(tr_client[idx].client_name, TRUE);
03689 
03690             /* indicate abort */
03691             i = 1;
03692             db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT);
03693             i = 0;
03694             db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT);
03695 
03696             return status;
03697          }
03698 
03699          if (debug_flag == 1)
03700             printf("Connection established to client \"%s\" on host %s\n",
03701                    tr_client[idx].client_name, tr_client[idx].host_name);
03702          if (debug_flag == 2)
03703             cm_msg(MINFO, "cm_transition",
03704                    "cm_transition: Connection established to client \"%s\" on host %s",
03705                    tr_client[idx].client_name, tr_client[idx].host_name);
03706 
03707          /* call RC_TRANSITION on remote client with increased timeout */
03708          old_timeout = rpc_get_option(hConn, RPC_OTIMEOUT);
03709          rpc_set_option(hConn, RPC_OTIMEOUT, timeout);
03710 
03711          /* set FTPC protocol if in async mode */
03712          if (async_flag == ASYNC)
03713             rpc_set_option(hConn, RPC_OTRANSPORT, RPC_FTCP);
03714 
03715          if (debug_flag == 1)
03716             printf("Executing RPC transition client \"%s\" on host %s...\n",
03717                    tr_client[idx].client_name, tr_client[idx].host_name);
03718          if (debug_flag == 2)
03719             cm_msg(MINFO, "cm_transition",
03720                    "cm_transition: Executing RPC transition client \"%s\" on host %s...",
03721                    tr_client[idx].client_name, tr_client[idx].host_name);
03722 
03723          t0 = ss_millitime();
03724 
03725          status = rpc_client_call(hConn, RPC_RC_TRANSITION, transition,
03726                                   run_number, error, errstr_size, tr_client[idx].sequence_number);
03727 
03728          t1 = ss_millitime();
03729 
03730          /* reset timeout */
03731          rpc_set_option(hConn, RPC_OTIMEOUT, old_timeout);
03732 
03733          /* reset protocol */
03734          if (async_flag == ASYNC)
03735             rpc_set_option(hConn, RPC_OTRANSPORT, RPC_TCP);
03736 
03737          if (debug_flag == 1)
03738             printf("RPC transition finished client \"%s\" on host %s in %d ms with status %d\n",
03739                    tr_client[idx].client_name, tr_client[idx].host_name, t1 - t0, status);
03740          if (debug_flag == 2)
03741             cm_msg(MINFO, "cm_transition",
03742                    "cm_transition: RPC transition finished client \"%s\" on host %s in %d ms with status %d",
03743                    tr_client[idx].client_name, tr_client[idx].host_name, t1 - t0, status);
03744 
03745          if (errstr != NULL) {
03746             if (strlen(error) < 2)
03747                sprintf(errstr, "Unknown error %d from client \'%s\' on host %s", status,
03748                        tr_client[idx].client_name, tr_client[idx].host_name);
03749             else
03750                memcpy(errstr, error,
03751                       (INT) strlen(error) + 1 < (INT) errstr_size ? (INT) strlen(error) + 1 : errstr_size);
03752          }
03753 
03754          if (status != CM_SUCCESS) {
03755             /* indicate abort */
03756             i = 1;
03757             db_set_value(hDB, 0, "/Runinfo/Start abort", &i, sizeof(INT), 1, TID_INT);
03758             i = 0;
03759             db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT);
03760 
03761             free(tr_client);
03762             return status;
03763          }
03764       }
03765    }
03766 
03767    if (tr_client)
03768       free(tr_client);
03769 
03770    if (debug_flag == 1)
03771       printf("\n---- Transition %s finished ----\n", trname);
03772    if (debug_flag == 2)
03773       cm_msg(MINFO, "cm_transition", "cm_transition: ---- Transition %s finished ----", trname);
03774 
03775    /* set new run state in database */
03776    if (transition == TR_START || transition == TR_RESUME)
03777       state = STATE_RUNNING;
03778 
03779    if (transition == TR_PAUSE)
03780       state = STATE_PAUSED;
03781 
03782    if (transition == TR_STOP)
03783       state = STATE_STOPPED;
03784 
03785    if (transition == TR_STARTABORT)
03786       state = STATE_STOPPED;
03787 
03788    size = sizeof(state);
03789    status = db_set_value(hDB, 0, "Runinfo/State", &state, size, 1, TID_INT);
03790    if (status != DB_SUCCESS)
03791       cm_msg(MERROR, "cm_transition", "cannot set Runinfo/State in database");
03792 
03793    /* send notification message */
03794    str[0] = 0;
03795    if (transition == TR_START)
03796       sprintf(str, "Run #%d started", run_number);
03797    if (transition == TR_STOP)
03798       sprintf(str, "Run #%d stopped", run_number);
03799    if (transition == TR_PAUSE)
03800       sprintf(str, "Run #%d paused", run_number);
03801    if (transition == TR_RESUME)
03802       sprintf(str, "Run #%d resumed", run_number);
03803    if (transition == TR_STARTABORT)
03804       sprintf(str, "Run #%d start aborted", run_number);
03805 
03806    if (str[0])
03807       cm_msg(MINFO, "cm_transition", str);
03808 
03809    /* lock/unlock ODB values if present */
03810    db_find_key(hDB, 0, "/Experiment/Lock when running", &hKey);
03811    if (hKey) {
03812       if (state == STATE_STOPPED)
03813          db_set_mode(hDB, hKey, MODE_READ | MODE_WRITE | MODE_DELETE, TRUE);
03814       else
03815          db_set_mode(hDB, hKey, MODE_READ, TRUE);
03816    }
03817 
03818    /* flush online database */
03819    if (transition == TR_STOP)
03820       db_flush_database(hDB);
03821 
03822    /* execute/stop programs on stop */
03823    if (transition == TR_STOP) {
03824       str[0] = 0;
03825       size = sizeof(str);
03826       db_get_value(hDB, 0, "/Programs/Execute on stop run", str, &size, TID_STRING, TRUE);
03827       if (str[0])
03828          ss_system(str);
03829 
03830       db_find_key(hDB, 0, "/Programs", &hRootKey);
03831       if (hRootKey) {
03832          for (i = 0;; i++) {
03833             status = db_enum_key(hDB, hRootKey, i, &hKey);
03834             if (status == DB_NO_MORE_SUBKEYS)
03835                break;
03836 
03837             db_get_key(hDB, hKey, &key);
03838 
03839             /* don't check "execute on xxx" */
03840             if (key.type != TID_KEY)
03841                continue;
03842 
03843             size = sizeof(program_info);
03844             status = db_get_record(hDB, hKey, &program_info, &size, 0);
03845             if (status != DB_SUCCESS) {
03846                cm_msg(MERROR, "cm_transition", "Cannot get program info record");
03847                continue;
03848             }
03849 
03850             if (program_info.auto_stop)
03851                cm_shutdown(key.name, FALSE);
03852          }
03853       }
03854    }
03855 
03856 
03857    /* indicate success */
03858    i = 0;
03859    db_set_value(hDB, 0, "/Runinfo/Transition in progress", &i, sizeof(INT), 1, TID_INT);
03860 
03861    if (errstr != NULL)
03862       strlcpy(errstr, "Success", errstr_size);
03863 
03864    return CM_SUCCESS;
03865 }

INT cm_yield ( INT  millisec  ) 

Central yield functions for clients. This routine should be called in an infinite loop by a client in order to give the MIDAS system the opportunity to receive commands over RPC channels, update database records and receive events.

Parameters:
millisec Timeout in millisec. If no message is received during the specified timeout, the routine returns. If millisec=-1, it only returns when receiving an RPC_SHUTDOWN message.
Returns:
CM_SUCCESS, RPC_SHUTDOWN

Definition at line 3979 of file midas.c.

Referenced by analyze_run(), check_abort(), close_channels(), cmd_idle(), command_loop(), lazy_copy(), loop_online(), main(), scan_fragment(), server_loop(), and tr_stop().

03980 {
03981    INT status;
03982    BOOL bMore;
03983    static DWORD last_checked = 0;
03984 
03985    /* check for ctrl-c */
03986    if (_ctrlc_pressed)
03987       return RPC_SHUTDOWN;
03988 
03989    /* check for available events */
03990    if (rpc_is_remote()) {
03991       bMore = bm_poll_event(TRUE);
03992       if (bMore)
03993          status = ss_suspend(0, 0);
03994       else
03995          status = ss_suspend(millisec, 0);
03996 
03997       return status;
03998    }
03999 
04000    /* check alarms once every 10 seconds */
04001    if (!rpc_is_remote() && ss_time() - last_checked > 10) {
04002       al_check();
04003       last_checked = ss_time();
04004    }
04005 
04006    bMore = bm_check_buffers();
04007 
04008    if (bMore) {
04009       /* if events available, quickly check other IPC channels */
04010       status = ss_suspend(0, 0);
04011    } else {
04012       /* mark event buffers for ready-to-receive */
04013       bm_mark_read_waiting(TRUE);
04014 
04015       status = ss_suspend(millisec, 0);
04016 
04017       /* unmark event buffers for ready-to-receive */
04018       bm_mark_read_waiting(FALSE);
04019    }
04020 
04021    return status;
04022 }

int tr_compare ( const void *  arg1,
const void *  arg2 
)

Definition at line 3167 of file midas.c.

Referenced by cm_transition1().

03168 {
03169    return ((TR_CLIENT *) arg1)->sequence_number - ((TR_CLIENT *) arg2)->sequence_number;
03170 }


Midas DOC Version 3.0.0 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel - Doxygen - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Tamsen Schurman - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk