From 006aae023c4bb96a6d25eebb72dc405620873fa6 Mon Sep 17 00:00:00 2001 From: cvs Date: Mon, 6 Nov 2000 13:04:56 +0000 Subject: [PATCH] Main server program for FOCUS --- sinqhm/focus_srv_main.c | 2609 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 2609 insertions(+) create mode 100755 sinqhm/focus_srv_main.c diff --git a/sinqhm/focus_srv_main.c b/sinqhm/focus_srv_main.c new file mode 100755 index 00000000..a21d68d7 --- /dev/null +++ b/sinqhm/focus_srv_main.c @@ -0,0 +1,2609 @@ +#define IDENT "1A01" +/* +** +--------------------------------------------------------------+ +** | Paul Scherrer Institute | +** | SINQ Division | +** | | +** | This software may be used freely by non-profit organizations.| +** | It may be copied provided that the name of P.S.I. and of the | +** | author is included. Neither P.S.I. nor the author assume any | +** | responsibility for the use of this software outside of P.S.I.| +** +--------------------------------------------------------------+ +** +** Module Name . . . . . . . . : [...SinqHM]FOCUS_srv_main.c +** +** Author . . . . . . . . . . : D. Maden +** Date of creation . . . . . . : Mar 2000 +** +** Updates: +** 1A01 7-Mar-2000 DM Initial version. +**--------------------------------------------------------------------------- +** FOCUS_srv_main.c is the main program of a SINQ Histogram Memory process +** for the FOCUS TOF spectrometer at SINQ. It acts as an intermediary between +** host software, which believes that it is talking to a single version of +** SinqHM_srv, and 3 copies of SinqHM_srv on 3 different front-end processors, +** each of which is histogramming data from one of the 3 detector banks on +** FOCUS. +** +** Communication between FOCUS_srv and the client is via TCP/IP protocol. +** +** To compile and link this program for VxWorks on PSS123, use: +** + ccvx '-DINST=""' FOCUS_srv_main.c + ccvx '-DINST=""' FOCUS_srv_server.c + ccvx '-DINST=""' FOCUS_srv_routines.c +** where + ccvx = ccppc -O0 \ + -mcpu=603 \ + -I${WIND_BASE}/target/h \ + -fno-builtin \ + -fno-for-scope \ + -nostdinc \ + -DCPU=PPC603 \ + -D_GNU_TOOL \ + -gdwarf -c -Wimplicit +** and +** = FOCUS or ... + + ldppc -o FOCUS_srv.o -r FOCUS_srv_main.o \ + FOCUS_srv_routines.o \ + FOCUS_srv_server.o + +** and, on the target, +** +** -> ld < /home/pss123/aco/maden/wind/SinqHM/FOCUS/NEW/FOCUS_srv.o +** -> sp FOCUS_main, \ +** , , , , , , , +** ^ ^ ^ ^ ^ ^ ^ ^ +** Name of Host | | | | | | | | +** for Mittel-Bnk+ | | | | | | | +** # Counters in Mittel- + | | | | | | +** Bank | | | | | | +** Name of Host for Ober-Bank ---+ | | | | | +** # Counters in Ober-Bank --------------+ | | | | +** Name of Host for Unter-Bank ------------------+ | | | +** # Counters in Unter-Bank -----------------------------+ | | +** Port number of Bank Servers (dflt = 2500) --------------------+ | +** Our Port number as a Server (dflt = 2400) ------------------------------+ +** e.g. +** sp FOCUS_main, "localhost", 150, "lnse05.vme", 117, "lnse06.vme", 116 +** or sps FOCUS_main, "localhost", 150, "lnse05.vme", 117, "lnse06.vme", 116 +**==================================================================== +*/ +#include "vxWorks.h" +#include "taskLib.h" +#include "msgQLib.h" +#include "sockLib.h" +#include "inetLib.h" +#include "sysLib.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Get POSIX signal definitions. */ +#include +#include /* Get POSIX mem mgmnt definitions. */ +#include /* Get POSIX wait definitions. */ +/* +**==================== Global Definitions ===================================== +*/ +#include "SinqHM_def.h" +#include "FOCUS_gbl.h" + + extern char *vxWorksVersion; /* Version string of vxWorks */ + extern char *creationDate; /* Creation Date string of vxWorks */ +/* +**============================================================================= +** Local routines. +**-------------------------------------------------------------------------- +** FOCUS_server: This is the Child Process Code for FOCUS_srv. +** +** Set up TCP/IP port for operations with client, accept his +** connection and perform services for him. +** +** Note: There must be NO return from this function. +*/ + int FOCUS_server ( +/* ============ +*/ pid_t parent_pid, + SEM_ID sem, + int index, + int pkt_size, + int suspend_flag, + int *iret) { /* Return a status to parent here: + ** 0 = all OK + ** -1 = sigaction error. + ** -2 = socket or bind error with cnct_skt. + ** -3 = listen error with cnct_skt. + ** -4 = socket or bind error with clnt_skt. + ** -5 = failed to connect to a slave mstr. + ** -6 = SQHM_CNCT error response from slave. + ** -7 = socket or bind error with child. + ** -8 = failed to connect to a slave srvr. + */ + int status; + int i, is, nbytes, bytes_to_come; + char recd[80]; + char *p_nxt_byte; + int cnct_skt, rw_skt, clnt_skt, serve_port; + struct sockaddr_in rmt_sockname; + int rmt_sockname_len; + char *buff_pntr; + int port; + + sigset_t proc_sigmask; + struct sigaction sig_action; + + struct req_buff_struct my_req_bf; + struct rply_buff_struct my_rply_bf; + +/*============================================================================ +*/ + *iret = 0; /* Assume initialisation will be OK */ + + port = FS_port + index; + + StrJoin (FS_name[index], sizeof (FS_name[0]), taskName (get_pid ()), ""); + + if (suspend_flag != 0) { + printf ("\n%s: Suspending ..\n", FS_name[index]); + taskSuspend (0); /* We've been told to suspend ourself, .. + ** .. presumably for debug reasons. + */ + printf ("\n%s: Suspension ended!\n", FS_name[index]); + } +/*============================================================================ +** Define our signal mask first and define an action routine to catch +** the SIGINT signal our parent will send us when he wants us to exit. +*/ + status = sigemptyset (&proc_sigmask); + status = sigprocmask (SIG_SETMASK, &proc_sigmask, NULL); + + status = sigemptyset (&sig_action.sa_mask); + sig_action.sa_handler = FS_catch_int_signal; + sig_action.sa_flags = 0; + if (sigaction (SIGINT, &sig_action, NULL) == -1) { + getErrno (&FS_errno); + perror ("sigaction error:"); + *iret = -1; /* Tell our parent we've given up */ + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } +/*============================================================================ +** Create a TCP/IP socket for communication, bind it and listen. +*/ + FS_chld_cnct_skt[index] = 0; + cnct_skt = socket_bind (port, FS_name[index]); + if (cnct_skt == -1) { + *iret = -2; /* Tell our parent we've given up */ + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } + + status = listen (cnct_skt, 1); + if (status != 0) { + close (cnct_skt); + perror (StrJoin (recd, sizeof (recd), + FS_name[index], " -- cnct_skt listen error")); + *iret = -3; /* Tell our parent we've given up */ + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } +/*============================================================================ +** Now open client connections to each of the Slaves +*/ + my_req_bf.bigend = htonl (0x12345678); + my_req_bf.cmnd = htonl (SQHM_CNCT); + my_req_bf.u.cnct.max_pkt = htonl (pkt_size); + my_req_bf.u.cnct.strt_mode = 0; + for (i = 0; i < FS_n_slaves; i++) { + if (FS_slv_active[i]) { + /* + ** Create a socket and bind it + */ + clnt_skt = socket_bind (0, FS_name[index]); + if (clnt_skt == -1) { + *iret = -4; /* Tell our parent we've given up */ + FS_close_all (index); /* Shut down any client cnct'ns we've made */ + close (cnct_skt); + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } + /* + ** Make a connection to Master-server in slave + */ + rmt_sockname_len = sizeof (FS_rmt_socknam[0]); + status = connect (clnt_skt, (struct sockaddr *) &FS_rmt_socknam[i], + rmt_sockname_len); + if (status == -1) { + StrJoin (recd, sizeof (recd), + ": error connecting to master in ", FS_slaves[i]); + perror (StrJoin (recd, sizeof (recd), FS_name[index], recd)); + *iret = -5; /* Tell our parent we've given up */ + close (clnt_skt); + FS_close_all (index); /* Shut down any client cnct'ns we've made */ + close (cnct_skt); + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } + /* + ** Send SQHM_CNCT command to Master-server and get response + */ + status = rqst_send_get (clnt_skt, &my_req_bf, sizeof (my_req_bf), + &my_rply_bf, sizeof (my_rply_bf), + &FS_bytes_got, &FS_bytes_put, FS_name[index]); + if (!status || (ntohl (my_rply_bf.status) != KER__SUCCESS)) { + if (ntohl (my_rply_bf.status) != KER__SUCCESS) { + printf ("\n%s: error response to SQHM_CNCT request to %s.\n", + FS_name[index], FS_slaves[i]); + } + *iret = -6; /* Tell our parent we've given up */ + close (clnt_skt); + FS_close_all (index); /* Shut down any client cnct'ns we've made */ + close (cnct_skt); + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } + close (clnt_skt); + serve_port = ntohl (my_rply_bf.u.cnct.port); + FS_pkt_siz[index][i] = ntohl (my_rply_bf.u.cnct.pkt_size); + /* + ** Create a socket for talking to our server in slave and bind + */ + clnt_skt = socket_bind (0, FS_name[index]); + if (clnt_skt == -1) { + *iret = -7; /* Tell our parent we've given up */ + FS_close_all (index); /* Shut down any client cnct'ns we've made */ + close (cnct_skt); + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } + /* + ** Make a connection to our server in slave + */ + rmt_sockname = FS_rmt_socknam[i]; + rmt_sockname.sin_port = htons (serve_port); + rmt_sockname_len = sizeof (rmt_sockname); + status = connect (clnt_skt, (struct sockaddr *) &rmt_sockname, + rmt_sockname_len); + if (status == -1) { + StrJoin (recd, sizeof (recd), + ": error connecting to server in ", FS_slaves[i]); + perror (StrJoin (recd, sizeof (recd), FS_name[index], recd)); + *iret = -8; /* Tell our parent we've given up */ + close (clnt_skt); + FS_close_all (index); /* Shut down any client cnct'ns we've made */ + close (cnct_skt); + is = semGive (sem); /* Let our parent continue */ + exit (KER__BAD_VALUE); + } + FS_skt[index][i] = clnt_skt; + } + } +/*============================================================================ +** Tell parent our cnct port is set up and waiting by releasing +** semaphore so that our parent can continue. The parent will then +** send a message to the client telling him which port he is to use. +*/ + FS_chld_cnct_skt[index] = cnct_skt; + is = semGive (sem); + if (is != OK) { + kill (parent_pid, SIGUSR1); /* Inform parent that we are in trouble */ + printf ("\n%s -- sem release error\n", FS_name[index]); + close (FS_chld_cnct_skt[index]); FS_chld_cnct_skt[index] = 0; + FS_close_all (index); /* Close connections to our servers */ + exit (KER__BAD_VALUE); + } +/*============================================================================ +** Wait for the client to connect to our port +*/ + rmt_sockname_len = sizeof (rmt_sockname); + rw_skt = accept (FS_chld_cnct_skt[index], + (struct sockaddr *) &rmt_sockname, &rmt_sockname_len); + if (rw_skt == -1) { + perror (StrJoin (recd, sizeof (recd), + FS_name[index], " -- cnct_skt accept error")); + close (FS_chld_cnct_skt[index]); FS_chld_cnct_skt[index] = 0; + FS_close_all (index); /* Close connections to our servers */ + kill (parent_pid, SIGUSR1); /* Inform parent that we are in trouble */ + exit (KER__BAD_VALUE); + } + FS_chld_rw_skt[index] = rw_skt; +/* +**------------------------------------------------------------------------- +** Here is the main recv loop +*/ + main_loop: +/*========= +*/ bytes_to_come = sizeof (my_req_bf); /* Read a command */ + p_nxt_byte = (char *) &my_req_bf; + while (bytes_to_come > 0) { + nbytes = recv (FS_chld_rw_skt[index], p_nxt_byte, bytes_to_come, 0); + if (nbytes <= 0) break; + FS_bytes_got += nbytes; + bytes_to_come -= nbytes; + p_nxt_byte += nbytes; + } + if ((bytes_to_come == 0) && + (ntohl (my_req_bf.bigend) == 0x12345678) && + (ntohl (my_req_bf.cmnd) != SQHM_CLOSE)) { + is = FS_do_command (index, FS_chld_rw_skt[index], pkt_size, + &my_req_bf, &my_rply_bf); + if (is) goto main_loop; /* Break out of loop on error */ + } +/* +** End of the main recv loop +**------------------------------------------------------------------------- +** Get here if we drop out of the "recv" loop. +** This should only happen on getting a SQHM_CLOSE message or if our +** client closes his socket without sending a SQHM_CLOSE message. +** Anything else is a fatal error. +*/ + close (FS_chld_rw_skt[index]); FS_chld_rw_skt[index] = 0; + close (FS_chld_cnct_skt[index]); FS_chld_cnct_skt[index] = 0; + /* + ** Check the various error conditions + */ + if (bytes_to_come != 0) { /* Was a complete request read? */ + /* No, it may be a network error, in which case + ** nbytes is -1, or nothing was read, which + ** indicates that our client simply closed + ** his connection (forgetting to send a + ** SQHM_CLOSE message), or the client has + ** screwed up the protocol! */ + if (nbytes == -1) { + /* It's a network error */ + perror (StrJoin (recd, sizeof (recd), + FS_name[index], " -- rw_skt recv error")); + status = KER__EXIT_SIGNAL; + }else if (bytes_to_come == sizeof (my_req_bf)) { + /* Our client simply closed his connection. + ** Treat this as normal. */ + printf ("\n%s exiting.\n", FS_name[index]); + status = KER__SUCCESS; + }else { + printf ("\n%s -- rw_skt recv wrong number of bytes: %d\n", + FS_name[index], nbytes); + status = KER__EXIT_SIGNAL; + } + }else if (ntohl (my_req_bf.bigend) != 0x12345678) { + /* Network byte-order wrong! */ + printf ("\n%s -- big-endian/little-endian problem!\n" + " Buffer received in non-network byte order!\n", FS_name[index]); + status = KER__EXIT_SIGNAL; + }else if (ntohl (my_req_bf.cmnd) == SQHM_CLOSE) { + /* SQHM_CLOSE request received. This is normal */ + printf ("\n%s exiting.\n", FS_name[index]); + status = KER__SUCCESS; + }else { + /* Unrecognised request received! */ + printf ("\n%s -- unrecognised command received: 0x%x\n", + FS_name[index], ntohl (my_req_bf.cmnd)); + status = KER__EXIT_SIGNAL; + } + + FS_close_all (index); /* Close connections to our servers */ + kill (parent_pid, SIGUSR1); /* Inform parent that we are exiting */ + exit (status); + } +/* +**-------------------------------------------------------------------------- +*/ + void FS_catch_signal (int signo) { +/* =============== +** Action Routine for catching signals from Child Processes. +** +** This routine is specific to FOCUS_srv. +*/ + pid_t my_pid; + + my_pid = get_pid (); + if (FS_dbg_lev0) printf ("\nFS_catch_signal: " + "Signal %d received by PID 0x%x.\n", signo, my_pid); + switch (signo) { + case SIGUSR1: /* A child is about to exit. */ + FS_cnt_SIGUSR1++; + sleep (1); /* Give it a chance to disappear! */ + break; + default: + printf ("\nFS_catch_signal: Unexpected signal received " + "by PID 0x%x: %d.\n", my_pid, signo); + } + } +/* +**--------------------------------------------------------------------------*/ + void FS_catch_int_signal (int signo) { +/* =================== +** Action Routine for catching SIGINT signals. This is a signal +** from the parent to get its child to exit. An exit will be performed. +** +** This routine is specific to FOCUS_srv. +*/ + int i, j; + pid_t my_pid; + + my_pid = get_pid (); + /* + ** Try to find our index by searching the PID list + */ + if (my_pid == FS_pids[0]) { + ; /* Should not get here - there's no Filler + ** for FOCUS_srv! */ + }else { + for (i = MAX_CLIENTS; i > 0; i--) if (my_pid == FS_pids[i]) break; + if (i > 0) { + if (FS_chld_rw_skt[i] != 0) { + printf ("\nClosing r/w socket of task %s\n", FS_name[i]); + close (FS_chld_rw_skt[i]); FS_chld_rw_skt[i] = 0; + } + if (FS_chld_cnct_skt[i] != 0) { + printf ("\nClosing connect socket of task %s\n", FS_name[i]); + close (FS_chld_cnct_skt[i]); FS_chld_cnct_skt[i] = 0; + } + for (j = 0; j < FS_n_slaves; j++) { + if (FS_skt[i][j] != 0) { + printf ("\nClosing client socket of task %s to %s\n", + FS_name[i], FS_slaves[i]); + close (FS_skt[i][j]); FS_skt[i][j] = 0; + } + } + } + } + + if (FS_dbg_lev0) printf ("\nFS_catch_int_signal: " + "Signal %d received by PID 0x%x.\n", signo, my_pid); + switch (signo) { + case SIGINT: /* A SIGINT signal has been received. Exit. */ + exit (KER__SUCCESS); + break; + default: + printf ("\nFS_catch_int_signal: " + "Unexpected signal %d received by PID 0x%x.\n", signo, my_pid); + } + } +/* +**-------------------------------------------------------------------------- +** FS_cleanup_children: Find out which child(ren) have exited and +** update the list of task PID's so the associated +** task slot becomes free. +** +** If FILLER should be present but has fallen off, then any +** active children will be told to exit and we shall set our +** state to "deconfig". +*/ + void FS_cleanup_children ( +/* =================== +*/ int max_chld, /* The size of the pids array */ + pid_t *pids, /* Array of pids. Index 0 is FILLER */ + int *pcnt_SIGUSR1, /* Flag set on SIGUSR1 signals whenever + ** a child exits. */ + int verbose, /* If true, report what's going on */ + char **tsk_names, + char *filler_name) { + + int i, status, n_active, do_newline = False; + char *t_name; + pid_t pid; + + if (pids[0] != 0) { + if (verbose) printf ("\n ... checking state of %s ...", filler_name); + t_name = taskName (pids[0]); + if (t_name == NULL) { + if (verbose) printf (" it has exited."); + pids[0] = 0; + }else { + if (verbose) printf (" it is still active."); + } + if (verbose) do_newline = True; + } + + n_active = 0; + for (i = 1; i <= max_chld; i++) { + if (pids[i] != 0) { + if (verbose) printf ("\n ... checking state of %s ...", tsk_names[i]); + t_name = taskName (pids[i]); + if (t_name == NULL) { + if (verbose) printf (" it has exited."); + pids[i] = 0; + }else { + if (verbose) printf (" it is still active."); + n_active += 1; + } + if (verbose) do_newline = True; + } + } + if (do_newline) printf ("\n"); + if (pcnt_SIGUSR1 != NULL) *pcnt_SIGUSR1 = 0; + + if ((filler_name[0] != NIL) && /* Must we force a de-config? */ + (pids[0] == 0) && + (n_active > 0)) { + for (;;) { /* Loop for ever till programmed! */ + printf ("\nThe filler process, %s, has terminated abnormally.\n" + "A de-configure must be forced\n" + "This has not yet been programmed.\n" + "Re-boot the histogram memory!!\n", filler_name); + sleep (5); + } + } + } +/* +**-------------------------------------------------------------------------- +** FS_close_all: Shut down any active client cnct'ns +*/ + int FS_close_all ( +/* ============ +*/ int index) { + + int i, status; + char recd[80]; + struct req_buff_struct my_req_bf; + struct rply_buff_struct my_rply_bf; + + my_req_bf.bigend = htonl (0x12345678); + my_req_bf.cmnd = htonl (SQHM_CLOSE); + for (i = 0; i < FS_n_slaves; i++) { + if (FS_skt[index][i] != 0) { + status = send (FS_skt[index][i], + (char *) &my_req_bf, sizeof (my_req_bf), 0); + if (status == -1) { + perror (StrJoin (recd, sizeof (recd), + FS_name[index], "/rqst_send_get: send error")); + } + close (FS_skt[index][i]); + FS_skt[index][i] = 0; + } + } + } +/* +**-------------------------------------------------------------------------- +** FS_close_down_offspring: Close down FILLER and, if directed, +** other children too. +*/ + int FS_close_down_offspring ( +/* ======================= +*/ int harshness, + int max_chld, + pid_t *pids, + int *exit_stat, + int *pcnt_SIGUSR1, /* Flag set on SIGUSR1 signals + ** whenever a child exits. */ + int verbose, /* If true, report what's going on */ + char **tsk_names, + char *filler_name) { + + int i, j; + int n_children, new_c = 0; + char buff[132]; + + n_children = 0; /* See if any server children are active */ + for (i = 1; i <= max_chld; i++) { + if (pids[i] != 0) n_children += 1; + } + if (n_children > 0) { /* If so, only proceed if asked to be ruthless */ + if (harshness == 0) { + printf ("\nDe-configure error. "); + if (n_children == 1) sprintf (buff, "1 server is"); + if (n_children != 1) sprintf (buff, "%d servers are", n_children); + printf ("%s still active.\n", buff); + return False; + }else { + if (n_children == 1) sprintf (buff, " -- 1 server is still active. It"); + if (n_children != 1) sprintf (buff, " -- %d servers are still active. " + "They", n_children); + printf ("\n%s will be terminated.\n", buff); + } + } + + FS_kill_children (max_chld, pids, + tsk_names, filler_name); /* Kill FILLER and any server children */ + sleep (1); /* Give them chance to exit */ + FS_cleanup_children (max_chld, pids, /* Update the PIDs */ + pcnt_SIGUSR1, verbose, tsk_names, filler_name); + + for (j = 0; j < n_children; j++) { /* Check to see if all gone */ + if (pids[0] == 0) new_c = 0; else new_c = 1; /* Count remainder */ + for (i = max_chld; i > 0; i--) { + if (pids[i] != 0) new_c += 1; + } + if (new_c == 0) break; + sleep (1); + FS_cleanup_children (max_chld, pids, + pcnt_SIGUSR1, verbose, tsk_names, filler_name); + } + if (new_c != 0) { + printf (" ... failed to tidy up. %d children still active.\n", new_c); + return False; + }else { + return True; + } + } +/* +**-------------------------------------------------------------------------- +** FS_deconfig_all: Deconfigure any active slaves. +** +** This routine is specific to FOCUS_srv. +*/ + int FS_deconfig_all (int harshness) { +/* =============== +*/ + int i, iret, all_ok = True; + struct req_buff_struct rqst; + struct rply_buff_struct reply; + + rqst.bigend = htonl (0x12345678); /* Set up the deconfig request */ + rqst.cmnd = htonl (SQHM_DECONFIG); + rqst.u.decnfg.sub_code = htonl (harshness); + /* + ** Loop sending it to active slaves + */ + for (i = 0; i < FS_n_slaves; i++) { + if (FS_slv_active[i]) { + iret = FS_send_cmnd_to_mstr (&FS_rmt_socknam[i], + &rqst, sizeof (rqst), &reply, + &FS_bytes_got, &FS_bytes_put); + if (iret && (ntohl (reply.status) == KER__SUCCESS)) { + FS_slv_active[i] = False; + }else { + all_ok = False; + } + } + } + return all_ok; + } +/* +**-------------------------------------------------------------------------- +** FS_do_command: Action routine for an SQHM_??? command. +** The command is processed (including returning a +** status response message). +** +** This routine is specific to FOCUS_srv. +*/ + int FS_do_command ( +/* ============= +*/ int index, + int skt, + int pkt_size, + struct req_buff_struct *rqst, + struct rply_buff_struct *reply) { + + int status, indx, is, suspendMode, i, j, sub_cmnd; + int txt_len, txt_offset, bytes_to_go, harshness; + int my_first_bin, my_nbins, my_bytes_per_bin, my_hist_no; + int my_sub_code, my_x_lo, my_nx, my_y_lo, my_ny, my_xdim, my_h_slct; + time_t secs; + char *msge, *p_buff, *p_txt; + + reply->bigend = htonl (0x12345678); /* Put in the "endian" flag. */ + rply_status_setup (reply, KER__SUCCESS, 0, "All OK"); + + switch (ntohl (rqst->cmnd)) { + + case SQHM_CLOSE: /* Close the connection. */ + return False; /* Do nothing. */ + + case SQHM_CNCT: /* Make a new connection. */ + printf ("\n%s: connecting ...", FS_name[index]); + + time (&secs); + secs = secs - FS_start_time; + reply->u.cnct.up_time = htonl (secs); + + if (!FS_cfgn_done) { /* Check we've been configured */ + printf (" but not yet configured!\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not configured", &FS_bytes_put); + }else if (index != 0) { + printf (" but not issued to SinqHM-master!\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not SinqHM-master", &FS_bytes_put); + }else { + pkt_size = ntohl (rqst->u.cnct.max_pkt); + if ((pkt_size < 1024) || (pkt_size > 8192)) pkt_size = 8192; + pkt_size = pkt_size & ~3; /* Ensure pkt_size is multiple of 4 */ + indx = FS_make_child (FOCUS_server, 100, + ntohl (rqst->u.cnct.strt_mode), pkt_size, + MAX_CLIENTS, FS_pids, FS_chld_exit_status, + &FS_cnt_SIGUSR1, "FSserv"); + if (indx <= 0) { /* Child created and ready? */ + printf ("\n%s: creation of child failed: %d.\n", + FS_name[0], indx); + switch (indx) { + case -1: msge = "Spawn failed"; break; + case -2: msge = "No more ports"; break; + case -3: msge = "Time-out of child start-up"; break; + case -4: msge = "Child could not get started"; break; + default: msge = "Bad status from make_child"; + } + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_CREATE, + indx, msge, &FS_bytes_put); + }else { /* Yes, child is up and ready. */ + reply->u.cnct.port = htonl (FS_port + indx); + reply->u.cnct.pkt_size = htonl (pkt_size); + reply->u.cnct.hm_mode = htonl (FS_mode_ALL); + reply->u.cnct.n_hists = htonl (FS_hi_cntr - FS_lo_cntr + 1); + reply->u.cnct.num_bins = htonl (FS_hi_bin - FS_lo_bin + 1); + reply->u.cnct.bytes_per_bin = htonl (FS_bpb); + reply->u.cnct.curr_hist = htonl (0); + reply->u.cnct.max_block = htonl (memFindMax ()); /* Max free mem */ + reply->u.cnct.total_bytes = htonl (FS_totl_bytes); + reply->u.cnct.lo_cntr = htonl (FS_lo_cntr); + reply->u.cnct.lo_bin = htonl (FS_lo_bin); + reply->u.cnct.compress = htonl (FS_compress); + printf (" %s started. Packet size = %d.\n", FS_name[indx], pkt_size); + is = FS_rply_status_send (skt, reply, &FS_bytes_put); + } + } + if (!is) + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + return is; + + case SQHM_CONFIG: + printf ("\n%s: Configure ..", FS_name[index]); + if (FS_cfgn_done) { + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Already configured", &FS_bytes_put); + printf (" already configured!\n"); + return False; + } + + FS_free_memory (NULL); /* There should be no memory allocated but + ** go and release it anyway! + */ + is = FS_do_config (skt, rqst, reply); /* No, do the config */ + if (!is) { + FS_rply_status_send (skt, reply, &FS_bytes_put); + return False; + }else { + FS_cfgn_done = True; + is = FS_rply_status_send (skt, reply, &FS_bytes_put); + if (!is) + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + return is; + } + + case SQHM_DAQ: /* Start or stop data acquisition. + ** Simply forward to our slaves. */ + printf ("\n%s: SQHM_DAQ", FS_name[index]); + if (!FS_cfgn_done) { /* Configured yet? */ + FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, /* No */ + "Not configured", &FS_bytes_put); + printf (" -- not configured!\n"); + return False; + } + sub_cmnd = ntohl (rqst->u.daq.sub_cmnd); + if (sub_cmnd == DAQ__CLR) printf ("/DAQ__CLR:"); + if (sub_cmnd == DAQ__GO) printf ("/DAQ__GO:"); + if (sub_cmnd == DAQ__INH) printf ("/DAQ__INH:"); + if (sub_cmnd == DAQ__STOP) printf ("/DAQ__STOP:"); + if (sub_cmnd == DAQ__TST) printf ("/DAQ__TST:"); + + is = FS_do_daq (index, sub_cmnd, rqst, reply); + + if (FS_dsbl_mask == 0) { + printf (" data acquisition is active.\n"); + }else { + printf (" data acquisition is inhibited.\n"); + } + + is = FS_rply_status_send (skt, reply, &FS_bytes_put); + if (!is) + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + return is; + + case SQHM_DBG: /* Set debug parameters. + ** Just do this locally. Do not + ** pass on to slaves. */ + FS_dbg_mask = ntohl (rqst->u.dbg.mask); + FS_dbg_lev0 = ((FS_dbg_mask & 1) != 0) ? 1 : 0; + FS_dbg_lev1 = ((FS_dbg_mask & 2) != 0) ? 1 : 0; + FS_dbg_lev2 = ((FS_dbg_mask & 4) != 0) ? 1 : 0; + FS_dbg_lev3 = ((FS_dbg_mask & 8) != 0) ? 1 : 0; + printf ("\n%s: Debug mask = 0x%x\n", FS_name[index], FS_dbg_mask); + is = FS_rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, + NULL, &FS_bytes_put); + if (!is) + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + return is; + + case SQHM_DECONFIG: /* Close down any servers and then deconfigure + ** our slaves */ + printf ("\n%s: De-configure", FS_name[index]); + if (!FS_cfgn_done) { /* Anything to do? */ + printf (" -- already de-configured!\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, + NULL, &FS_bytes_put); + }else if (index != 0) { + printf (" -- not issued to Master Server!\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not Master Server", &FS_bytes_put); + }else { + harshness = ntohl (rqst->u.decnfg.sub_code); /* Pick out "harshness" */ + is = FS_close_down_offspring (harshness, + MAX_CLIENTS, FS_pids, FS_chld_exit_status, + &FS_cnt_SIGUSR1, FS_dbg_lev0, FS_p_names, ""); + if (is) { + is = FS_deconfig_all (harshness); + if (is) { + printf (" done.\n"); + FS_cfgn_done = False; + is = FS_rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, + NULL, &FS_bytes_put); + }else { + printf ("\nFailed! Problem deconfiguring slaves.\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, is, + "Problem deconfiguring slaves", &FS_bytes_put); + } + }else { + printf ("\nFailed! Problem terminating children.\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, is, + "Problem terminating children", &FS_bytes_put); + } + FS_free_memory (NULL); /* Release all reserved memory */ + } + if (!is) + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + return is; + + case SQHM_EXIT: /* Rundown */ + printf ("\n%s: Run-down ...", FS_name[index]); + if (index != 0) { + printf (" -- not issued to Master Server!\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not SinqHM-master", &FS_bytes_put); + }else if (FS_cfgn_done) { + printf (" -- not issued to SinqHM-master!\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not SinqHM-master", &FS_bytes_put); + }else { + rqst->u.decnfg.sub_code = htonl (1); /* Set "harshness" = 1 */ + is = FS_close_down_offspring ( + ntohl (rqst->u.decnfg.sub_code), /* Pick out "harshness" */ + MAX_CLIENTS, FS_pids, FS_chld_exit_status, + &FS_cnt_SIGUSR1, FS_dbg_lev0, FS_p_names, ""); + if (is) { + if (FS_cfgn_done) { + printf (" deconfiguring ..."); + is = FS_deconfig_all (1); + if (is) { + printf (" done.\n"); + FS_cfgn_done = False; + is = FS_rply_status_setup_and_send (skt, reply, KER__SUCCESS, 0, + NULL, &FS_bytes_put); + }else { + printf (" WARNING: deconfig failed.\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, + is, "Problem deconfiguring", &FS_bytes_put); + } + } + }else { + printf (" WARNING: problem terminating children.\n"); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, is, + "Problem terminating children", &FS_bytes_put); + } + FS_free_memory (NULL); /* Release all reserved memory */ + } + if (!is) + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + return True; + + case SQHM_IDENT: /* Give info on software identification. */ + txt_len = IDENT_MSGE_LEN; + txt_offset = 0; + p_buff = calloc (txt_len, 1); /* Get a buffer for text info */ + if (p_buff == NULL) { + printf ("\n%s -- SQHM_IDENT: failed to get buffer!\n", + FS_name[index]); + FS_rply_status_setup_and_send (skt, reply, KER__BAD_ALLOC, 0, + "Failed to get buffer for composing Ident", &FS_bytes_put); + return False; + } + time (&secs); + secs = secs - FS_start_time; + reply->u.ident.up_time = htonl (secs); + reply->u.ident.n_extra_bytes = htonl (IDENT_MSGE_LEN); + p_txt = p_buff; + + reply->u.ident.offset_vxWorks_ident = htons (txt_offset); + StrJoin (p_txt, txt_len, vxWorksVersion, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_vxWorks_date = htons (txt_offset); + StrJoin (p_txt, txt_len, creationDate, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_instr = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_inst, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_def_ident = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_def_ident, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_main_ident = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_main_ident, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_main_date = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_main_date, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_server_ident = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_serv_ident, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_server_date = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_serv_date, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_filler_ident = htons (txt_offset); + StrJoin (p_txt, txt_len, "", ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_filler_date = htons (txt_offset); + StrJoin (p_txt, txt_len, "", ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_routines_ident = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_rout_ident, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + reply->u.ident.offset_sinqhm_routines_date = htons (txt_offset); + StrJoin (p_txt, txt_len, FS_rout_date, ""); + i = strlen (p_txt) + 1; + txt_offset += i; p_txt += i; txt_len -= i; + + is = FS_rply_status_send (skt, reply, &FS_bytes_put); + /* + ** Now send the data + */ + p_txt = p_buff; + bytes_to_go = IDENT_MSGE_LEN; + while (bytes_to_go > 0) { + i = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go; + is = send (skt, p_txt, i, 0); + if (is > 0) { + FS_bytes_put += is; + bytes_to_go -= is; + p_txt += is; + }else { + free (p_buff); + printf ("\n%s -- SQHM_IDENT: failed to send extra data!\n", + FS_name[index]); + return False; /* Fatal error on send */ + } + } + free (p_buff); + return True; + + case SQHM_PROJECT: /* Read a projected "rectangle" of the HM. */ + if (!FS_cfgn_done) { /* Check we've been configured */ + printf ("\n%s -- projecting but not yet configured!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not configured", &FS_bytes_put); + return False; + }else { + if (FS_dbg_lev0) printf ("\n%s -- projecting ...", FS_name[index]); + my_sub_code = ntohl (rqst->u.project.sub_code); + my_x_lo = ntohl (rqst->u.project.x_lo); + my_nx = ntohl (rqst->u.project.nx); + my_y_lo = ntohl (rqst->u.project.y_lo); + my_ny = ntohl (rqst->u.project.ny); + my_xdim = ntohl (rqst->u.project.xdim); + my_h_slct = ntohl (rqst->u.project.nhist); + is = FS_do_project (index, reply, skt, pkt_size, + my_sub_code, my_x_lo, my_nx, my_y_lo, my_ny, my_xdim, my_h_slct); + if (!is) { + printf ("\n%s -- SQHM_PROJECT fatal error sending status reply or " + "histo data.\n", FS_name[index]); + }else { + if (FS_dbg_lev0) printf (" done.\n"); + } + return is; + } + + case SQHM_READ: /* Read a section of the HM. */ + if (!FS_cfgn_done) { /* Check we've been configured */ + printf ("\n%s -- reading but not yet configured!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not configured", &FS_bytes_put); + return False; + }else { + if (FS_dbg_lev0) printf ("\n%s -- reading ...", FS_name[index]); + my_hist_no = ntohl (rqst->u.read.hist_no); + my_first_bin = ntohl (rqst->u.read.first_bin); + my_nbins = ntohl (rqst->u.read.n_bins); + is = FS_do_read (index, reply, skt, pkt_size, + my_nbins, my_first_bin, my_hist_no); + if (!is) { + printf ("\n%s -- SQHM_READ fatal error sending status reply or " + "histo data.\n", FS_name[index]); + }else { + if (FS_dbg_lev0) printf (" done.\n"); + } + return is; + } + + case SQHM_SELECT: /* SQHM_SELECT still needs to be programmed. */ + printf ("\n%s: Select ...", FS_name[index]); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_VALUE, 0, + "Not yet available!", &FS_bytes_put); + if (!is) { + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + }else { + printf (" not yet implemented!\n"); + } + return is; + + case SQHM_STATUS: /* Get-Status request */ + if (FS_dbg_lev0) printf ("\n%s: Status ...", FS_name[index]); + /* + ** Build up info + */ + reply->status = htonl (KER__SUCCESS); /* Indicate success */ + strcpy ((char *) &reply->sub_status, /* Set up the Ident */ + SINQHM_DEF_ID); /* This does not need htonl! */ + reply->u.status.max_n_hists = htonl (N_HISTS_MAX); + reply->u.status.max_num_bins = htonl (N_BINS_MAX + 1); + reply->u.status.max_srvrs = MAX_CLIENTS; + reply->u.status.max_block = htonl (memFindMax ()); /* Max free mem */ + if (!FS_cfgn_done) { + reply->u.status.cfg_state = 0; + reply->u.status.n_hists = 0; + reply->u.status.curr_hist = 0; + reply->u.status.num_bins = 0; + reply->u.status.act_srvrs = 0; + reply->u.status.bytes_per_bin = 0; + reply->u.status.compress = 0; + reply->u.status.daq_now = 0; + reply->u.status.filler_mask = 0; + reply->u.status.tsi_status = 0; + reply->u.status.flags = 0; + reply->u.status.dt_or_dts.both = 0; + reply->u.status.num_bad_events = 0; + }else { + reply->u.status.cfg_state = htonl (FS_mode_ALL); + reply->u.status.n_hists = htonl (FS_hi_cntr - FS_lo_cntr + 1); + reply->u.status.curr_hist = htons (0); + reply->u.status.num_bins = htonl (FS_hi_bin - FS_lo_bin + 1); + + for (j = 0, i = 1; i <= MAX_CLIENTS; i++) if (FS_pids[i] != 0) j++; + reply->u.status.act_srvrs = j; + + reply->u.status.bytes_per_bin = FS_bpb; + reply->u.status.compress = FS_compress; + reply->u.status.daq_now = htons (FS_dsbl_mask); + reply->u.status.filler_mask = htons (FS_srv_masks[0]); + reply->u.status.tsi_status = htonl (0); + reply->u.status.flags = htonl (0); + reply->u.status.dt_or_dts.both = htonl (0); + reply->u.status.num_bad_events = htonl (0); + } + time (&secs); + secs = secs - FS_start_time; + reply->u.status.up_time = htonl (secs); + + is = FS_rply_status_send (skt, reply, &FS_bytes_put); + if (FS_dbg_lev0) { + if (!is) { + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + }else { + printf (" has been sent.\n"); + } + } + return is; + + case SQHM_WRITE: /* Write a section of the HM. + ** + ** NOTE: always call FS_do_write, even if not configured + ** ==== since network data has always to be read. + */ + printf ("\n%s: writing ...", FS_name[index]); + my_hist_no = ntohl (rqst->u.write.hist_no); + my_first_bin = ntohl (rqst->u.write.first_bin); + my_nbins = ntohl (rqst->u.write.n_bins); + my_bytes_per_bin = ntohl (rqst->u.write.bytes_per_bin); + is = FS_do_write (index, rqst, reply, skt, pkt_size, + my_nbins, my_first_bin, my_bytes_per_bin, my_hist_no); + if (!is) { + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + }else { + printf (" done.\n"); + } + return is; + + case SQHM_ZERO: + if (!FS_cfgn_done) { /* Check we've been configured */ + printf ("\n%s -- zeroing but not yet configured!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_STATE, 0, + "Not configured", &FS_bytes_put); + return False; + }else { + printf ("\n%s -- zeroing ...", FS_name[index]); + + my_hist_no = ntohl (rqst->u.zero.hist_no); + my_first_bin = ntohl (rqst->u.zero.first_bin); + my_nbins = ntohl (rqst->u.zero.n_bins); + + FS_do_zero (reply, index, my_nbins, my_first_bin, my_hist_no); + is = FS_rply_status_send (skt, reply, &FS_bytes_put); + if (!is) { + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + }else { + printf (" done.\n"); + } + return is; + } + + default: + printf ("\n%s: Unrecognised command received ...\n", FS_name[index]); + is = FS_rply_status_setup_and_send (skt, reply, KER__BAD_VALUE, 0, + "Unrecognised command!", &FS_bytes_put); + if (!is) { + printf ("\n%s -- send of status reply failed.\n", FS_name[index]); + }else { + printf (" it has been acknowledged.\n"); + } + return is; + } + printf ("\nSoftware error in do_command - switch statement completed!\n"); + return False; + } +/* +**-------------------------------------------------------------------------- +** FS_do_config: ... +*/ + int FS_do_config ( +/* ============ +*/ int skt, + struct req_buff_struct *request, + struct rply_buff_struct *reply) { + + int i, n_bytes_got, iret, return_status; + uint bytes_needed, n_extra, n_edges, n_banks; + uint sizeof_edge_arr, n_bins, flag; + uint lo_cntr, hi_cntr, n_cntrs, slv_lo_cntr, slv_hi_cntr; + char *p_addr; + struct tof_bank *p_bank; + struct req_buff_struct *my_rqu; + struct rply_buff_struct my_rply; + + FS_mode_ALL = ntohl (request->u.cnfg.mode); /* The histogramming mode */ + + FS_mode = FS_mode_ALL & (~SQHM__SUB_MODE_MSK); + FS_mode_DEBUG = FS_mode_ALL & SQHM__DEBUG; + FS_mode_UD = FS_mode_ALL & SQHM__UD; + FS_mode_BO = FS_mode_ALL & SQHM__BO_MSK; + FS_mode_STROBO = FS_mode_ALL & SQHM__STROBO; + FS_mode_REFLECT = FS_mode_ALL & SQHM__REFLECT; + FS_mode_NO_STAT = FS_mode_ALL & SQHM__NO_STAT; + + if (FS_mode != SQHM__TOF) { /* The mode must be TOF */ + printf ("\nFS_do_config: mode is not TOF\n"); + return False; + } + /* + ** For complicated configurations, there may be more config + ** data to be read. If so n_extra_bytes will be non-zero. + */ + n_extra = ntohl (request->u.cnfg.u.tof.n_extra_bytes); + if (n_extra != 0) { + /* + ** There is extra data to be read. Get buffer space for the + ** extra stuff plus space to copy over what has already been + ** read so that everything is in a contiguous buffer. + */ + bytes_needed = n_extra + sizeof (*request); + bytes_needed = (bytes_needed + 3) & (~3); /* Round up to multiple of 4 */ + p_addr = malloc (bytes_needed); + if (p_addr == NULL) { + printf ("\nFS_do_config:" + " cannot allocate memory for extra config data!\n"); + net_flush (skt, n_extra); + rply_status_setup (reply, KER__BAD_ALLOC, 0, + "Failed to get buffer for extra config data"); + return False; + } + my_rqu = (struct req_buff_struct *) p_addr; + memcpy (p_addr, request, sizeof (*request)); /* Copy in what has already + ** been read. */ + bytes_needed = n_extra; /* And read the rest */ + p_addr += sizeof (*request); + while (bytes_needed > 0) { + n_bytes_got = recv (skt, p_addr, bytes_needed, 0); + if (n_bytes_got <= 0) break; + FS_bytes_got += n_bytes_got; + bytes_needed -= n_bytes_got; + p_addr += n_bytes_got; + } + if (n_bytes_got < 0) { + printf ("\n" + "%s -- R/W-Socket recv error\n" + "%s -- Connection will be closed.\n", FS_name[0], FS_name[0]); + rply_status_setup (reply, KER__BAD_VALUE, 0, "recv failed"); + free (my_rqu); + return False; + } + }else { + my_rqu = request; + } + + n_bins = ntohl (my_rqu->u.cnfg.u.tof.edge_0.n_bins); + flag = ntohl (my_rqu->u.cnfg.u.tof.edge_0.flag); + if ((flag & FLAG__VAR_BIN) != 0) { + sizeof_edge_arr = OffsetOf (struct tof_edge_arr, edges) + + ((n_bins + 1) * sizeof (uint)); + FS_compress = 0; + }else { + sizeof_edge_arr = sizeof (struct tof_edge_arr); + FS_compress = ntohl (my_rqu->u.cnfg.u.tof.edge_0.edges[1]) - + ntohl (my_rqu->u.cnfg.u.tof.edge_0.edges[0]); + } + p_bank = (struct tof_bank *) ( + (char *) &my_rqu->u.cnfg.u.tof.edge_0 + sizeof_edge_arr); + + + n_edges = ntohs (my_rqu->u.cnfg.u.tof.n_edges); + n_banks = ntohs (my_rqu->u.cnfg.u.tof.n_banks); + if ((n_edges != 1) || (n_banks != 1)) { + printf ("\nFS_do_config: configuration is too complex.\n"); + return False; + } + lo_cntr = ntohl (p_bank->first); + n_cntrs = ntohl (p_bank->n_cntrs); + hi_cntr = lo_cntr + n_cntrs -1; + /* + ** Now loop sending the configuration request to + ** all slaves. + */ + return_status = True; /* Assume all will be OK */ + for (i = 0; i < FS_n_slaves; i++) { + if (FS_slaves[i] != NULL) { + slv_lo_cntr = (FS_lo_det[i] > lo_cntr) ? FS_lo_det[i] : lo_cntr; + slv_hi_cntr = (FS_hi_det[i] < hi_cntr) ? FS_hi_det[i] : hi_cntr; + if (slv_hi_cntr >= slv_lo_cntr) { + FS_slv_active[i] = True; + p_bank->first = htonl (slv_lo_cntr - FS_lo_det[i]); + p_bank->n_cntrs = htonl (slv_hi_cntr - slv_lo_cntr + 1); + iret = FS_send_cmnd_to_mstr (&FS_rmt_socknam[i], + my_rqu, (sizeof (*request) + n_extra), + &my_rply, &FS_bytes_got, &FS_bytes_put); + if (iret && (ntohl (my_rply.status) != KER__SUCCESS)) { + reply->status = my_rply.status; + reply->sub_status = my_rply.sub_status; + StrJoin (reply->u.message, sizeof (reply->u.message), + FS_slaves[i], ": "); + StrJoin (reply->u.message, sizeof (reply->u.message), + reply->u.message, my_rply.u.message); + FS_slv_active[i] = False; + return_status = False; + break; + } + }else { + FS_slv_active[i] = False; + } + } + } + + if (!return_status) { /* If any error, force deconfig */ + FS_deconfig_all (1); + return return_status; + } + + FS_lo_cntr = lo_cntr; + FS_hi_cntr = hi_cntr; + FS_lo_bin = 0; + FS_hi_bin = n_bins - 1; + FS_bpb = ntohl (p_bank->bytes_per_bin); + FS_totl_bytes = FS_bpb * (FS_hi_cntr - FS_lo_cntr + 1) * + (FS_hi_bin - FS_lo_bin + 1); + + if (n_extra != 0) free (my_rqu); + return return_status; + } +/* +**-------------------------------------------------------------------------- +** FS_do_daq: Handle an SQHM_DAQ command. +*/ + int FS_do_daq ( +/* ========= +*/ int indx, + int sub_cmnd, + struct req_buff_struct *request, + struct rply_buff_struct *reply) { + + int i, iret, all_ok = True; + + if (sub_cmnd == DAQ__TST) { /* DAQ__TST is special - we just give the .. + ** .. caller a snapshot of our status .. + ** .. without invoking our slaves. */ + reply->status = htonl (KER__SUCCESS); + reply->u.daq.daq_was = htons (FS_dsbl_mask); + reply->u.daq.filler_mask = htons (FS_srv_masks[0]); + reply->u.daq.server_mask = htons (FS_srv_masks[indx]); + reply->u.daq.daq_now = reply->u.daq.daq_was; + }else { + /* + ** Claim the sem to avoid race conditions with other threads + */ + if (FS_use_sem_tmo) { + iret = semTake (FS_sem_daq, FS_sem_tmo); + }else { + iret = semTake (FS_sem_daq, WAIT_FOREVER); + } + /* + ** Loop sending the SQHM_DAQ command to active slaves + */ + request->bigend = htonl (0x12345678); + request->cmnd = htonl (SQHM_DAQ); + request->u.daq.sub_cmnd = htonl (sub_cmnd); + for (i = 0; i < FS_n_slaves; i++) { + if (FS_slv_active[i]) { + if (indx == 0) { /* If we are the master-server, send it to the + ** master-servers in the slaves. */ + iret = FS_send_cmnd_to_mstr (&FS_rmt_socknam[i], + request, sizeof (*request), reply, + &FS_bytes_got, &FS_bytes_put); + if (!iret || (ntohl (reply->status) != KER__SUCCESS)) all_ok=False; + }else { + iret = rqst_send_get (FS_skt[indx][i], request, sizeof (*request), + reply, sizeof (*reply), + &FS_bytes_got, &FS_bytes_put, FS_name[indx]); + if (!iret || (ntohl (reply->status) != KER__SUCCESS)) all_ok=False; + } + } + } + if (!all_ok) { /* If error, go no further! */ + semGive (FS_sem_daq); + return all_ok; + } + reply->status = htonl (KER__SUCCESS); + reply->u.daq.daq_was = htons (FS_dsbl_mask); + reply->u.daq.filler_mask = htons (FS_srv_masks[0]); + reply->u.daq.server_mask = htons (FS_srv_masks[indx]); + switch (sub_cmnd) { + case DAQ__CLR: + FS_dsbl_mask &= (~FS_srv_masks[indx]); /* Clear user's mask bit. */ + break; + case DAQ__GO: + FS_dsbl_mask &= (~FS_srv_masks[0]); /* Clear "filler's" mask bit. */ + break; + case DAQ__INH: + FS_dsbl_mask |= FS_srv_masks[indx]; /* Set user's mask bit */ + break; + case DAQ__STOP: + FS_dsbl_mask |= FS_srv_masks[0]; /* Set "filler's" mask bit. */ + } + reply->u.daq.daq_now = htons (FS_dsbl_mask); /* Complete the status + ** response message */ + iret = semGive (FS_sem_daq); /* Release the semaphore */ + } + return all_ok; + } +/* +**-------------------------------------------------------------------------- +** FS_do_project: Read a "rectangular" region of Hist Mem and send it +** to the client. +*/ + int FS_do_project ( +/* ============= +*/ int index, + struct rply_buff_struct *rply_bf, + int rw_skt, + int pkt_size, + uint sub_code, + uint x_lo, + uint nx, + uint y_lo, + uint ny, + uint xdim, + uint h_slct) { +/* +** Read a "rectangular" region of Hist Mem and send it +** to the client. +*/ + uint my_bin_lo, my_bin_hi; + uint my_cntr_lo, my_cntr_hi; + int i, is, nput, my_daq_save; + uint my_nbins, bins_to_go, bytes_in_buff, bytes_to_go; + uchar *buff_pntr; + char recd[132], *nxt; + struct req_buff_struct my_rqst; + struct rply_buff_struct my_rply; + + register union { + void *base; + uchar *ch; + usint *i2; + uint *i4; + } my_pntr0, my_pntr1; + + rply_status_setup (rply_bf, KER__BAD_VALUE, 0, "Bad argument"); /* Assume .. + ** .. we shall find a bad arg */ +/*-------------------------------------------------------------------- +** There's no need to test the hist mode; it must be SQHM_TOF because +** SQHM_CONFIG rejects anything else. So, start by checking arguments. +*/ + if ((sub_code & PROJECT__1_DIM) != 0) { + printf ("\n%s -- SQHM_PROJECT: SQHM__TOF+PROJECT__1_DIM not yet " + "implemented!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, 0, + "Not yet implemented", &FS_bytes_put); + return OK; + } + /* Check the arguments */ + /* Check that counter numbers are in range */ + my_cntr_lo = y_lo; + if ((my_cntr_lo < FS_lo_cntr) || + (my_cntr_lo > FS_hi_cntr)) { + printf ("\n%s -- SQHM_PROJECT: Bad y_lo!\n", FS_name[index]); + is = FS_rply_status_send (rw_skt, rply_bf, &FS_bytes_put); + return OK; + } + my_cntr_hi = (ny != 0) ? (y_lo + ny - 1) : FS_hi_cntr; + if ((my_cntr_hi < my_cntr_lo) || (my_cntr_hi > FS_hi_cntr)) { + printf ("\n%s -- SQHM_PROJECT: Bad ny!\n", FS_name[index]); + is = FS_rply_status_send (rw_skt, rply_bf, &FS_bytes_put); + return OK; + } + /* Check that bin numbers are in range */ + my_bin_lo = x_lo; + if ((my_bin_lo < FS_lo_bin) || + (my_bin_lo > FS_hi_bin)) { + printf ("\n%s -- SQHM_PROJECT: Bad x_lo!\n", FS_name[index]); + is = FS_rply_status_send (rw_skt, rply_bf, &FS_bytes_put); + return OK; + } + my_bin_hi = (nx != 0) ? + (x_lo + nx - 1) : FS_hi_bin; + if ((my_bin_hi < my_bin_lo) || + (my_bin_hi > FS_hi_bin)) { + printf ("\n%s -- SQHM_PROJECT: Bad nx!\n", FS_name[index]); + is = FS_rply_status_send (rw_skt, rply_bf, &FS_bytes_put); + return OK; + } + /* + ** All the arguments have been checked. Reserve some space + ** for projecting the data. The amount of space that we + ** need for the projection depends on whether the + ** projection is onto the x-axis or y-axis. + */ + my_nbins = ((sub_code & PROJECT__ON_Y) == 0) ? + (my_bin_hi - my_bin_lo + 1) : (my_cntr_hi - my_cntr_lo + 1); + + my_pntr0.base = calloc (my_nbins, sizeof (uint)); + my_pntr1.base = calloc (my_nbins, sizeof (uint)); + if ((my_pntr0.base == NULL) || (my_pntr1.base == NULL)) { + printf ("\n%s -- SQHM_PROJECT: failed to get buffer!\n", + FS_name[index]); + FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_ALLOC, 0, + "Failed to get buffer for projecting data", &FS_bytes_put); + return OK; + free (my_pntr1.base); + } + /*----------------------------------------------------- + ** We got some buffer space so inhibit data acqu ... + */ + my_daq_save = FS_dsbl_mask & FS_srv_masks[index]; /* Remember the .. + ** .. state of our inhibit bit and disable data acq + ** .. if not already disabled by us. This is necessary + ** .. to prevent data "skewing" as we read out our + ** .. 3 slaves. */ + if (my_daq_save == 0) FS_do_daq (index, DAQ__INH, &my_rqst, &my_rply); + /*----------------------------------------------------- + ** ... then do the projection ... + */ + bins_to_go = FS_project_hm (index, pkt_size, + my_pntr0.base, my_pntr1.base, my_nbins, + sub_code, my_cntr_lo, my_cntr_hi, my_bin_lo, my_bin_hi); + if (bins_to_go <= 0) { + if (my_daq_save == 0) FS_do_daq (index, DAQ__CLR, &my_rqst, &my_rply); + perror (StrJoin (recd, sizeof (recd), + FS_name[index], "/FS_do_project: FS_project_hm error")); + free (my_pntr0.base); + free (my_pntr1.base); + return False; + } + /*----------------------------------------------------- + ** ... projection complete so let Filler continue and + ** send data back to client. + */ + if (my_daq_save == 0) FS_do_daq (index, DAQ__CLR, &my_rqst, &my_rply); + + rply_bf->u.project.n_bins = htonl (my_nbins); + rply_bf->u.project.bytes_per_bin = htonl (sizeof (uint)); + rply_bf->u.project.cnts_lo = htonl (0); + rply_bf->u.project.cnts_hi = htonl (0); + + if (rply_bf->bigend != 0x12345678) { /* If byte swapping needed, ... + ** .. then swap them! */ + for (i = 0; i < my_nbins; i++) my_pntr0.i4[i] = htonl (my_pntr0.i4[i]); + } + + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, 0, + NULL, &FS_bytes_put); + + bytes_to_go = my_nbins * sizeof (uint); + buff_pntr = (uchar *) my_pntr0.base; + + while (bytes_to_go > 0) { + nput = (bytes_to_go > pkt_size) ? pkt_size : bytes_to_go; + is = send (rw_skt, buff_pntr, nput, 0); + if (is > 0) { + FS_bytes_put += is; + bytes_to_go -= is; + buff_pntr += is; + }else { + free (my_pntr0.base); + free (my_pntr1.base); + return ERROR; /* Fatal error on send */ + } + } + free (my_pntr0.base); /* Release our bit of memory */ + free (my_pntr1.base); + return True; + } +/* +**-------------------------------------------------------------------------- +** FS_do_read: Read a consecutive region of 'nbins' bins of the +** Hist Mem starting with bin 'first' and send it to +** the client. +*/ + int FS_do_read ( +/* ========== +*/ int index, + struct rply_buff_struct *rply_bf, + int rw_skt, + int pkt_size, + uint nbins, + uint first, + uint hist_no) { + + register int i, my_fstbin, my_topbin; + int is, status, bytes_to_go, nput, nxtbin, nb; + int my_daq_save; + uint maxbins, my_nbins, bins_in_buff; + uint nxtbin_to_send, nbins_to_send, bytes_in_buff; + uint bins_to_go; + struct req_buff_struct my_rqst; + struct rply_buff_struct my_rply; + uchar *buff_pntr, *last_byte, *nxt; + uchar buff[pkt_size]; + + register union { + void *base; + uchar *ch; + usint *i2; + uint *i4; + } my_pntr, hm_pntr; +/*-------------------------------------------------------------------- +** There's no need to test the hist mode; it must be SQHM_TOF because +** SQHM_CONFIG rejects anything else. So, start by checking arguments. +*/ + maxbins = (FS_hi_cntr - FS_lo_cntr + 1) * (FS_hi_bin - FS_lo_bin + 1); + + if (hist_no == -1) { + /* Regard the histograms as 1 long array */ + if ((first == -1) && (nbins == -1)) { + /* The user just wants to read everything */ + my_fstbin = 0; + my_nbins = maxbins; + }else { + /* The user wants a part of the histogram data */ + if (first >= maxbins) { + if (FS_dbg_lev0) printf ( + "\n%s -- SQHM_READ: bad first_bin!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, + 0, "\"first_bin\" too big", &FS_bytes_put); + return is; + }else if ((nbins > maxbins) || ((first + nbins) > maxbins)) { + if (FS_dbg_lev0) printf ( + "\n%s -- SQHM_READ: bad n_bins!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, + 0, "\"n_bins\" too big", &FS_bytes_put); + return is; + } + my_fstbin = first; + my_nbins = nbins; + } + }else { + /* The user wants a part of the histogram of a single counter */ + if ((hist_no < FS_lo_cntr) || (hist_no > FS_hi_cntr)) { + if (FS_dbg_lev0) printf ( + "\n%s -- SQHM_READ: bad hist_no!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, + 0, "\"hist_no\" out of range", &FS_bytes_put); + return is; + }else if ((first < FS_lo_bin) || (first > FS_hi_bin)) { + if (FS_dbg_lev0) printf ( + "\n%s -- SQHM_READ: bad first_bin!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, + 0, "\"first_bin\" out of range", &FS_bytes_put); + return is; + }else if ((nbins > (FS_hi_bin - FS_lo_bin + 1)) || + ((first + nbins) > (FS_hi_bin + 1))) { + if (FS_dbg_lev0) printf ( + "\n%s -- SQHM_READ: bad n_bins!\n", FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, + 0, "\"n_bins\" out of range", &FS_bytes_put); + return is; + } + my_fstbin = (hist_no - FS_lo_cntr) * (FS_hi_bin - FS_lo_bin + 1) + first; + my_nbins = nbins; + } + /* + ** The args are OK. + ** Reserve some space for buffering the histogram data. + */ + my_pntr.base = NULL; + i = memFindMax (); /* Get size of biggest free memory block */ + if (i > (my_nbins * FS_bpb)) { /* If there's room to hold everything, + ** try to get it */ + bins_in_buff = my_nbins; + my_pntr.base = malloc (bins_in_buff * FS_bpb); + if (my_pntr.base == NULL) { + bins_in_buff = my_nbins/2; /* A fall-back position! */ + my_pntr.base = malloc (bins_in_buff * FS_bpb); + } + }else { + i = (i * 3)/4; /* there's not room to hold everything, so get less! */ + bins_in_buff = (i + FS_bpb - 1)/FS_bpb; + my_pntr.base = malloc (bins_in_buff * FS_bpb); + } + if (my_pntr.base == NULL ) { + if (FS_dbg_lev0) printf ( + "\n%s -- SQHM_READ: no buffer space available!\n", + FS_name[index]); + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__BAD_VALUE, + 0, "No buffer space", &FS_bytes_put); + return is; + } + /* + ** The args are OK and we have some buffer space. + ** Tell client he's about to get some data! + */ + rply_bf->u.read.first_bin = htonl (my_fstbin); + rply_bf->u.read.n_bins = htonl (my_nbins); + rply_bf->u.read.bytes_per_bin = htonl (FS_bpb); + rply_bf->u.read.cnts_lo = 0; /* \ cnts_lo and cnts_hi not */ + rply_bf->u.read.cnts_hi = 0; /* / yet implemented */ + is = FS_rply_status_setup_and_send (rw_skt, rply_bf, KER__SUCCESS, + 0, NULL, &FS_bytes_put); + + my_daq_save = FS_dsbl_mask & FS_srv_masks[index]; /* Remember the .. + ** .. state of our inhibit bit and disable data acq + ** .. if not already disabled by us. This is necessary + ** .. to prevent data "skewing" as we read out our + ** .. 3 slaves. */ + if (my_daq_save == 0) FS_do_daq (index, DAQ__INH, &my_rqst, &my_rply); + nxtbin_to_send = my_fstbin; + nbins_to_send = my_nbins; + bytes_in_buff = 0; + nxt = (char *) my_pntr.base; + while (nbins_to_send > 0) { + /* Read some histogram data into buffer */ + bins_to_go = FS_read_hm (index, pkt_size, + my_pntr.base, bins_in_buff, + nxtbin_to_send, (my_fstbin + my_nbins - 1)); + if (bins_to_go <= 0) { + perror (StrJoin (buff, pkt_size, + FS_name[index], "/FS_do_read: FS_read_hm error")); + free (my_pntr.base); + if (my_daq_save == 0) FS_do_daq (index, DAQ__CLR, &my_rqst, &my_rply); + return False; + } + nxt = (char *) my_pntr.base; + bytes_in_buff = bins_to_go * FS_bpb; + while (bytes_in_buff > 0) { /* Send data to user */ + bytes_to_go = (bytes_in_buff > pkt_size) ? pkt_size : bytes_in_buff; + is = send (rw_skt, nxt, bytes_to_go, 0); + if (is <= 0) { + perror (StrJoin (buff, pkt_size, + FS_name[index], "/FS_do_read: send error")); + free (my_pntr.base); + if (my_daq_save == 0) FS_do_daq (index, DAQ__CLR, &my_rqst, &my_rply); + return False; + } + FS_bytes_put += bytes_to_go; + bytes_in_buff -= bytes_to_go; + nxt += bytes_to_go; + } + nxtbin_to_send += bins_to_go; + nbins_to_send -= bins_to_go; + } + free (my_pntr.base); + /* + ** Read-out complete so let DAQ continue. + */ + if (my_daq_save == 0) FS_do_daq (index, DAQ__CLR, &my_rqst, &my_rply); + return True; + } +/* +**-------------------------------------------------------------------------- +** FS_do_write: Preset a consecutive region of the Hist Mem. The +** number of bins to preset is 'nbins' starting with +** bin 'first'. The data for the bins is read from +** the client. +*/ + int FS_do_write ( +/* =========== +*/ int index, + struct req_buff_struct *req_bf, + struct rply_buff_struct *rply_bf, + int rw_skt, + int pkt_size, + int nbins, + int first, + int bytes_per_bin, + int hist_no) { + return True; + } +/* +**-------------------------------------------------------------------------- +** FS_do_zero: Action routine for SQHM_ZERO command. +*/ + int FS_do_zero ( +/* =========== +*/ struct rply_buff_struct *reply, + int index, + int nbins, + int first_bin, + int hist_no) { + return True; + } +/* +**-------------------------------------------------------------------------- +** FS_free_memory: Free any memory allocated for FOCUS_srv +*/ + void FS_free_memory ( +/* ============== +*/ void *extras) { + + int i; + /* + ** Release a possible pending buffer + */ + free (extras); + /* + ** Release any allocated histogram buffer + */ + free (FS_base_addr); + FS_base_addr = NULL; + } +/* +**-------------------------------------------------------------------------- +** FS_kill_children: Send signals to all our offspring to cause +** them to terminate. +*/ + void FS_kill_children ( +/* ================ +*/ int max_chld, + pid_t *pids, + char **tsk_names, + char *filler_name) { + + int i, is; + + if (pids[0] != 0) { + printf (" .. closing down %s ..", filler_name); + is = kill (pids[0], SIGINT); + if (!is) printf ("\nBad status killing %s.\n", filler_name); + } + for (i = 1; i <= max_chld; i++) { + if (pids[i] != 0) { + printf ("\n Terminating %s ..", tsk_names[i]); + is = kill (pids[i], SIGINT); + if (is == ERROR) printf ("\nBad status killing %s.\n", tsk_names[i]); + } + } + } +/* +**-------------------------------------------------------------------------- +** FS_make_child: Find a free child index, create a child process and +** invoke procedure proc in the child procedure. +** Return value >= 0 if child successfully created; +** = -1 if error returned by fork; +** = -2 if there are too many children already; +** = -3 if time-out waiting for child to signal. +** < -3 the child indicated a start-up error. The +** child's error code is the return +** value + 3. +*/ + int FS_make_child ( +/* ============= +*/ int (* proc) (), /* The procedure to be started */ + int prty, /* The child's priority */ + int spnd, /* "Suspend" flag to help debug the child */ + int pkt_size, /* TCP/IP packet size to be used */ + int max_chld, /* The size of the following arrays */ + pid_t *pids, /* Array of PIDs of children */ + int *exit_stat, /* Array of children's exit stati */ + int *pcnt_SIGUSR1, /* Flag set on SIGUSR1 signals whenever + ** a child exits. */ + char *name) { /* Prefix for child's name */ + + int i, status, tmo; + pid_t created_pid; + char tsknam[20]; + SEM_ID my_sem; +/* +** Find a free PID index. Zero is not a permitted value. +*/ + for (i = 1; i <= max_chld; i++) if (pids[i] == 0) break; + + if (i > max_chld) { /* Free index found? */ + return -2; /* No, there are already too many children. */ + }else { + if (pcnt_SIGUSR1 != NULL) *pcnt_SIGUSR1 = 0; + my_sem = semBCreate (SEM_Q_FIFO, SEM_EMPTY); /* Create a claimed sem- + ** -aphore which the child can release when + ** it has finished its initialisation. */ + exit_stat[i] = 0; /* Zero child's status indicator */ + sprintf (tsknam, "%.*s%02d", (sizeof (tsknam) - 3), + name, i); /* Generate the child's name */ + created_pid = taskSpawn ( /* Make a child */ + tsknam, /* Name */ + prty, /* Priority */ + VX_FP_TASK, /* Options - fl.pt. usage assumed */ + 20000, /* Stack size */ + proc, /* The entry point */ + FS_pid, (int) my_sem, i, pkt_size, spnd, + (int) &exit_stat[i], + 0, 0, 0, 0); + if (created_pid == ERROR) { /* Error? */ + return -1; /* Yes. */ + }else { /* Parent */ + pids[i] = created_pid; + tmo = 1000; /* Normally give child 1000 ticks to .. + ** .. get going */ + if (spnd != 0) { + tmo = WAIT_FOREVER; /* But in debug mode, wait forever! */ + } + status = semTake (my_sem, tmo); /* Wait for child to get going */ + semDelete (my_sem); + if (status == ERROR) { /* Timeout? */ + taskDelete (pids[i]); /* Yes, kill child. */ + pids[i] = 0; + return -3; /* Return with error. */ + }else { /* No timeout so child is ready. */ + if (exit_stat[i] >= 0) { /* Did the child have a startup .. + ** .. problem */ + return i; /* No, so return its index */ + }else { + return (exit_stat[i] - 3); /* Yes, so return error */ + } + } + } + } + } +/* +**-------------------------------------------------------------------------- +** FS_project_hm: Project a block of histogram data. +** +** Return value = # of bins in buffer, each of size uint. +** Notes: +** This is an internal routine so all args are assumed to be OK. +*/ + int FS_project_hm ( +/* ============= +*/ int index, + int pkt_size, + uint *buff, /* Buffer to receive the data */ + uint *w_buff, /* Workspace */ + uint blen_in_bins, /* Size of buff and w_buff in bins */ + uint sub_code, /* 0 or PROJECT__ON_Y */ + uint lo_cntr, /* First counter wanted */ + uint hi_cntr, /* Last counter wanted */ + uint fst_bin, /* First bin wanted */ + uint lst_bin) { /* Last bin wanted */ + + int i, j, k, nx, ny, iret; + uint s_lo_cntr, s_hi_cntr, bytes_to_come; + uint f_cntr, l_cntr, n_cntr_got; + uint f_bin, l_bin, n_bins_got; + uchar *b_pntr; + struct req_buff_struct my_rq; + struct rply_buff_struct my_rp; + /* + ** There are 2 cases: project on x and project on y. + ** Project on x is expected to be the more common! + */ + if (sub_code != PROJECT__ON_Y) { + n_cntr_got = 0; /* Project on X */ + memset (buff, 0, (blen_in_bins * sizeof (uint))); /* Zero the buffer */ + for (i = 0; i < 3; i++) { /* Find which slave(s) has the wanted data */ + s_lo_cntr = FS_lo_det[i]; + s_hi_cntr = FS_hi_det[i]; + if (((s_lo_cntr >= lo_cntr) && (s_hi_cntr <= hi_cntr)) || + ((s_lo_cntr < lo_cntr) && (s_hi_cntr > hi_cntr)) || + ((s_lo_cntr < lo_cntr) && (s_hi_cntr >= lo_cntr)) || + ((s_lo_cntr <= hi_cntr) && (s_hi_cntr > hi_cntr))) { + f_cntr = (s_lo_cntr >= lo_cntr) ? 0 : (lo_cntr - s_lo_cntr); + l_cntr = (s_hi_cntr <= hi_cntr) ? (s_hi_cntr - s_lo_cntr) : + (hi_cntr - s_lo_cntr); + my_rq.bigend = htonl (0x12345678); + my_rq.cmnd = htonl (SQHM_PROJECT); + my_rq.u.project.sub_code = htonl (0); + my_rq.u.project.x_lo = htonl (fst_bin); + my_rq.u.project.nx = htonl (lst_bin - fst_bin + 1); + my_rq.u.project.y_lo = htonl (f_cntr); + my_rq.u.project.ny = htonl (l_cntr - f_cntr + 1); + my_rq.u.project.xdim = htonl (0); + my_rq.u.project.nhist = htonl (0); + iret = rqst_send_get (FS_skt[index][i], &my_rq, sizeof (my_rq), + &my_rp, sizeof (my_rp), + &FS_bytes_put, &FS_bytes_got, FS_name[index]); + if (!iret) {return 0;}; + if (ntohl (my_rp.status) != KER__SUCCESS) {return 0;}; + nx = ntohl (my_rp.u.project.n_bins); /* # of bins to be read */ + bytes_to_come = nx * ntohl (my_rp.u.project.bytes_per_bin); + b_pntr = (uchar *) w_buff; + while (bytes_to_come > 0) { + j = (bytes_to_come > pkt_size) ? pkt_size : bytes_to_come; + k = recv (FS_skt[index][i], b_pntr, j, 0); + if (k <= 0) {perror ("FS_project_hm"); return 0;} + bytes_to_come -= k; + b_pntr += k; + } + k = l_cntr - f_cntr + 1; + n_cntr_got += k; + lo_cntr += k; + for (k = 0; k < nx; k++) buff[k] += ntohl (w_buff[k]); + } + } + return nx; + }else { + n_cntr_got = 0; /* Project on Y */ + for (i = 0; i < 3; i++) { /* Find which slave(s) has the wanted data */ + s_lo_cntr = FS_lo_det[i]; + s_hi_cntr = FS_hi_det[i]; + if (((s_lo_cntr >= lo_cntr) && (s_hi_cntr <= hi_cntr)) || + ((s_lo_cntr < lo_cntr) && (s_hi_cntr > hi_cntr)) || + ((s_lo_cntr < lo_cntr) && (s_hi_cntr >= lo_cntr)) || + ((s_lo_cntr <= hi_cntr) && (s_hi_cntr > hi_cntr))) { + f_cntr = (s_lo_cntr >= lo_cntr) ? 0 : (lo_cntr - s_lo_cntr); + l_cntr = (s_hi_cntr <= hi_cntr) ? (s_hi_cntr - s_lo_cntr) : + (hi_cntr - s_lo_cntr); + my_rq.bigend = htonl (0x12345678); + my_rq.cmnd = htonl (SQHM_PROJECT); + my_rq.u.project.sub_code = htonl (PROJECT__ON_Y); + my_rq.u.project.x_lo = htonl (fst_bin); + my_rq.u.project.nx = htonl (lst_bin - fst_bin + 1); + my_rq.u.project.y_lo = htonl (f_cntr); + my_rq.u.project.ny = htonl (l_cntr - f_cntr + 1); + my_rq.u.project.xdim = htonl (0); + my_rq.u.project.nhist = htonl (0); + iret = rqst_send_get (FS_skt[index][i], &my_rq, sizeof (my_rq), + &my_rp, sizeof (my_rp), + &FS_bytes_put, &FS_bytes_got, FS_name[index]); + if (!iret) {return 0;}; + if (ntohl (my_rp.status) != KER__SUCCESS) {return 0;}; + ny = ntohl (my_rp.u.project.n_bins); /* # of elements to be read */ + bytes_to_come = ny * ntohl (my_rp.u.project.bytes_per_bin); + b_pntr = (uchar *) w_buff; + while (bytes_to_come > 0) { + j = (bytes_to_come > pkt_size) ? pkt_size : bytes_to_come; + k = recv (FS_skt[index][i], b_pntr, j, 0); + if (k <= 0) {perror ("FS_project_hm"); return 0;} + bytes_to_come -= k; + b_pntr += k; + } + for (k = 0; k < ny; k++) buff[n_cntr_got+k] = ntohl (w_buff[k]); + n_cntr_got += ny; + lo_cntr += ny; + } + } + return n_cntr_got; + } + } +/* +**-------------------------------------------------------------------------- +** FS_read_hm: Read a block of histogram data. +** +** Return value = # of bins read. +*/ + int FS_read_hm ( +/* ========== +*/ int index, + int pkt_size, + uchar *buff, /* Buffer to receive the data */ + uint blen_in_bins, /* Size of buff in bins */ + uint fst_bin, /* First bin wanted */ + uint lst_bin) { /* Last bin wanted */ + + int i, j, k, iret; + uint s_fst_bin, s_lst_bin, bins_per_hist; + uint f_bin, l_bin, bytes_to_come, n_bins_got; + struct req_buff_struct my_rq; + struct rply_buff_struct my_rp; + + bins_per_hist = FS_hi_bin - FS_lo_bin + 1; + n_bins_got = 0; + + for (i = 0; i < 3; i++) { /* Find which slave(s) has the wanted data */ + s_fst_bin = 0; + for (j = 0; j < i; j++) { + s_fst_bin += (FS_hi_det[j] - FS_lo_det[j] + 1) * bins_per_hist; + } + s_lst_bin = s_fst_bin + + (FS_hi_det[i] - FS_lo_det[i] + 1) * bins_per_hist - 1; + if (((s_fst_bin >= fst_bin) && (s_lst_bin <= lst_bin)) || + ((s_fst_bin < fst_bin) && (s_lst_bin > lst_bin)) || + ((s_fst_bin < fst_bin) && (s_lst_bin >= fst_bin)) || + ((s_fst_bin <= lst_bin) && (s_lst_bin > lst_bin))) { + f_bin = (s_fst_bin >= fst_bin) ? 0 : (fst_bin - s_fst_bin); + l_bin = (s_lst_bin <= lst_bin) ? (s_lst_bin - s_fst_bin) : + (lst_bin - s_fst_bin); + my_rq.bigend = htonl (0x12345678); + my_rq.cmnd = htonl (SQHM_READ); + my_rq.u.read.hist_no = htonl (-1); + my_rq.u.read.first_bin = htonl (f_bin); + my_rq.u.read.n_bins = htonl (l_bin - f_bin + 1); + iret = rqst_send_get (FS_skt[index][i], &my_rq, sizeof (my_rq), + &my_rp, sizeof (my_rp), + &FS_bytes_put, &FS_bytes_got, FS_name[index]); + if (!iret) {return 0;}; + if (ntohl (my_rp.status) != KER__SUCCESS) {return 0;}; + k = ntohl (my_rp.u.read.n_bins); /* # of bins to be read */ + bytes_to_come = k * FS_bpb; + while (bytes_to_come > 0) { + j = (bytes_to_come > pkt_size) ? pkt_size : bytes_to_come; + k = recv (FS_skt[index][i], buff, j, 0); + if (k <= 0) {perror ("FS_read_hm"); return 0;} + bytes_to_come -= k; + buff += k; + } + k = l_bin - f_bin + 1; + n_bins_got += k; + fst_bin += k; + } + } + return n_bins_got; + } +/* +**--------------------------------------------------------------------------*/ + int FS_rply_status_send ( +/* =================== +*/ int skt, + struct rply_buff_struct *rply_bf, + uint *cntr_out) { + + int is; + + is = send (skt, (char *) rply_bf, sizeof (*rply_bf), 0); + if (is == sizeof (*rply_bf)) { + *cntr_out += is; + return True; + }else { + return False; + } + } +/* +**--------------------------------------------------------------------------*/ + int FS_rply_status_setup_and_send ( +/* ============================= +*/ int skt, + struct rply_buff_struct *rply_bf, + int status, + int sub_status, + char *msg, + uint *cntr_out) { + + int is; + + rply_status_setup (rply_bf, status, sub_status, msg); + is = FS_rply_status_send (skt, rply_bf, cntr_out); + + return is; + } +/* +**-------------------------------------------------------------------------- +** FS_send_cmnd_to_mstr: Send command to Sinqm-Master process +** in a slave. +*/ + int FS_send_cmnd_to_mstr ( +/* ==================== +*/ struct sockaddr_in *rmt_sockname, + struct req_buff_struct *request, + int requ_len, + struct rply_buff_struct *reply, + uint *in_cntr, + uint *out_cntr) { + + int status, cnct_skt, rmt_sockname_len; + int bytes_to_come, nbytes; + char *p_nxt_byte; + struct sockaddr_in lcl_sockname; +/* +** Create a TCP/IP socket for connecting to SINQHM_SRV root and bind it. +*/ + cnct_skt = socket (AF_INET, SOCK_STREAM, 0); + if (cnct_skt == -1) failInet ("\nFS_send_cmnd_to_mstr: socket error."); + + setup_host (NULL, &lcl_sockname, 0, False); + status = bind (cnct_skt, (struct sockaddr *) &lcl_sockname, + sizeof (lcl_sockname)); + if (status == -1) failInet ("\nFS_send_cmnd_to_mstr: bind error."); +/* +** Connect to SINQHM_SRV root. +*/ + rmt_sockname_len = sizeof (*rmt_sockname); + status = connect (cnct_skt, (struct sockaddr *) rmt_sockname, + rmt_sockname_len); + if (status == -1) { + getErrno (&FS_errno); + failInet ("\nFS_send_cmnd_to_mstr: connect error"); + } + /* + ** Send the request to the server + */ + status = send (cnct_skt, (char *) request, requ_len, 0); + if (status == -1) failInet ("\nFS_send_cmnd_to_mstr -- send error"); + if (status != requ_len) { + printf ("\nFS_send_cmnd_to_mstr -- wrong number of bytes sent: %d %d\n", + status, requ_len); + return False; + } + *out_cntr += requ_len; +/* +** Wait for the status response. +*/ + bytes_to_come = sizeof (*reply); + p_nxt_byte = (char *) reply; + while (bytes_to_come > 0) { + nbytes = recv (cnct_skt, p_nxt_byte, bytes_to_come, 0); + if (nbytes <= 0) break; + *in_cntr += nbytes; + bytes_to_come -= nbytes; + p_nxt_byte += nbytes; + } + if (nbytes == -1) { + failInet ("\nFS_send_cmnd_to_mstr -- recv error"); + return False; + }else if (nbytes == 0) { + printf ("\nFS_send_cmnd_to_mstr -- server has closed connection!\n"); + return False; + }else if (ntohl (reply->bigend) != 0x12345678) { + /* Network byte-order wrong! */ + printf ("\nFS_send_cmnd_to_mstr -- big-endian/little-endian problem!\n" + " Buffer received in non-network byte order!\n"); + return False; + } + return True; + } +/* +**-------------------------------------------------------------------------- +** rqst_send_get: Send a network request and get reply +*/ + int rqst_send_get ( +/* ============= +*/ int skt, + struct req_buff_struct *rqst_bf, + int rq_len, + struct rply_buff_struct *rply_bf, + int rp_size, + int *out_cntr, + int *in_cntr, + char *tsk_name) { + + int status, bytes_to_come, nbytes, n_bytes_got; + char recd[80], *p_addr; + /* + ** Send the request to the server + */ + status = send (skt, (char *) rqst_bf, rq_len, 0); + if (status == -1) { + perror (StrJoin (recd, sizeof (recd), + tsk_name, "/rqst_send_get: send error")); + return False; + } + if (status != rq_len) { + printf ("\n%s/rqst_send_get: wrong number of bytes sent: %d %d\n", + tsk_name, status, rq_len); + return False; + } + *out_cntr += rq_len; +/* +** Wait for the response. +*/ + bytes_to_come = rp_size; + p_addr = (char *) rply_bf; + while (bytes_to_come > 0) { + n_bytes_got = recv (skt, p_addr, bytes_to_come, 0); + if (n_bytes_got <= 0) break; + *in_cntr += n_bytes_got; + bytes_to_come -= n_bytes_got; + p_addr += n_bytes_got; + } + if (n_bytes_got < 0) { + perror (StrJoin (recd, sizeof (recd), + tsk_name, "/rqst_send_get: recv error")); + return False; + }else if (n_bytes_got == 0) { + printf ("\n%s/rqst_send_get: zero bytes received!\n", tsk_name); + return False; + }else if (ntohl (rply_bf->bigend) != 0x12345678) { + printf ("\n%s/rqst_send_get: big-endian/little-endian problem!\n", + tsk_name); + return False; + } + return True; + } +/* +**-------------------------------------------------------------------------- +** setup_host: Setup Internet structures for a named host +*/ + int setup_host ( +/* ========== +*/ char *host, + struct sockaddr_in *sockname, + int port, + int verbose) { + + int i, j, k, l, m; + char my_host[64], my_addr[32]; + struct in_addr my_inet_addr; + + if (host == NULL) { + my_inet_addr.s_addr = 0; + }else { + if (strlen (host) >= sizeof (my_host)) return False; + for (i = 0; i <= strlen (host); i++) my_host[i] = tolower (host[i]); + /* + ** Try to convert the Internet address. First assume it is dot + ** notation. If this fails, see if we can recognise the name. + */ + my_inet_addr.s_addr = inet_addr (my_host); + if (my_inet_addr.s_addr == ERROR) { + if (strcmp (my_host, "localhost") == 0) { + my_inet_addr.s_addr = inet_addr ("127.0.0.1"); + }else { + i = sscanf (my_host, "lnse%d%n", &j, &k); + if ((i == 1) && (k == 6)) { + if (strcmp (&my_host[k], ".vme") == 0) { + sprintf (my_addr, "192.168.11.%d", j); /* "lnse??.vme" */ + }else { + sprintf (my_addr, "129.129.62.%d", (100+j)); /* "lnse??" */ + } + my_inet_addr.s_addr = inet_addr (my_addr); + }else { + i = sscanf (my_host, "psds%d%n", &j, &k); + if ((i == 1) && (k == 6) && (my_host[k] == NIL)) { + sprintf (my_addr, "129.129.62.%d", j); /* "psds??" */ + my_inet_addr.s_addr = inet_addr (my_addr); + } + } + } + } + } + if (my_inet_addr.s_addr == ERROR) { + printf ("\nsetup_host: Node \"%s\" is unknown.\n", host); + return False; + } + if (verbose) { + printf ("Host is %s ", host); + inet_ntoa_b (my_inet_addr, my_addr); + printf ("(%s),", my_addr); + printf (" Port %d.\n", port); + } + sockname->sin_family = AF_INET; + sockname->sin_port = htons (port); + sockname->sin_addr.s_addr = my_inet_addr.s_addr; + } +/* +**-------------------------------------------------------------------------- +** socket_bind: Setup an Internet socket and bind it to a port. +*/ + int socket_bind ( +/* =========== +*/ int port, + char *tsk_name) { + + int status, skt; + struct sockaddr_in sockname; + char recd[80]; + + skt = socket (AF_INET, SOCK_STREAM, 0); + if (skt == -1) { + perror (StrJoin (recd, sizeof (recd), tsk_name, + " -- socket error in socket_bind")); + return skt; + } + + setup_host (NULL, &sockname, port, False); + status = bind (skt, (struct sockaddr *) &sockname, sizeof (sockname)); + if (status != 0) { + close (skt); + perror (StrJoin (recd, sizeof (recd), tsk_name, + " -- bind error in socket_bind")); + return -1; + } + return skt; + } +/* +**============================================================================== +** Main line program +** ------------------ +**============================================================================*/ + int FOCUS_main ( +/* ========== +*/ char *hostM, int ndetM, + char *hostO, int ndetO, + char *hostU, int ndetU, + int c_port, /* Our port # as client */ + int s_port, /* Our port # for serving */ + int arg9, int suspend) { +/*============================================================================*/ + struct req_buff_struct req_buff; + struct rply_buff_struct rply_buff; + + int i, j, is, status, cntr; + int keep_going = True; + int bytes_to_come, n_bytes_got; + char *p_addr; + int cl_port; + struct sockaddr_in lcl_sockname; + struct sockaddr_in rmt_sockname; + int rmt_sockname_len; + int pkt_size; + time_t timer; + char buff[132]; + + sigset_t proc_sigmask; + struct sigaction sig_action; + +/*============================================================================ +*/ + if (suspend != 0) { + printf ("\nFOCUS_srv: Suspending ...\n"); + taskSuspend (0); /* We've been told to suspend ourself, .. + ** .. presumably for debug reasons. + */ + printf ("\nFOCUS_srv: Suspension ended!\n"); + } +/*============================================================================ +** Perform the initialisation of global variables ... +*/ + StrJoin (FS_inst, sizeof (FS_inst), INST, ""); /* Save the instr. + ** name in a global + */ + StrJoin (FS_def_ident, sizeof (FS_def_ident), SINQHM_DEF_ID, ""); + StrJoin (FS_main_ident, sizeof (FS_main_ident), IDENT, ""); + StrJoin (FS_main_date, sizeof (FS_main_date), __DATE__, ", "); + StrJoin (FS_main_date, sizeof (FS_main_date), FS_main_date, __TIME__); + time (&FS_start_time); /* Initialise the start time */ + FS_serv_ident[0] = NIL; + FS_serv_date[0] = NIL; + FS_rout_ident[0] = NIL; + FS_rout_date[0] = NIL; + + FS_cfgn_done = False; /* Force a configuration before we can do anything. */ + + FS_bytes_got = 0; FS_bytes_put = 0; + FS_dbg_mask = FS_dbg_lev0 = FS_dbg_lev1 = FS_dbg_lev2 = FS_dbg_lev3 = 0; + + FS_free_memory (NULL); /* Release memory (possibly) in case .. + ** .. of a restart of the program */ + if (FS_cnct_skt != 0) close (FS_cnct_skt); + if (FS_rw_skt != 0) close (FS_rw_skt); + FS_cnct_skt = FS_rw_skt = 0; + + for (i = 0; i <= MAX_CLIENTS; i++) { + FS_pids[i] = 0; + FS_chld_exit_status[i] = 0; + if (FS_chld_cnct_skt[i] != 0) close (FS_chld_cnct_skt[i]); + if (FS_chld_rw_skt[i] != 0) close (FS_chld_rw_skt[i]); + FS_chld_cnct_skt[i] = FS_chld_rw_skt[i] = 0; + FS_p_names[i] = &FS_name[i][0]; FS_name[i][0] = NIL; + for (j = 0; j <= 3; j++) { + if (FS_skt[i][j] != 0) {close (FS_skt[i][j]); FS_skt[i][j] = 0;} + } + FS_srv_masks[i] = (i == 0) ? 0x8000 : 1 << (i - 1); + } + if (FS_sem_daq == NULL) { + FS_sem_daq = semBCreate (SEM_Q_FIFO, SEM_FULL); /* Create a released sem- + ** aphore for guarding access to + ** FS_dsbl_mask */ + } + FS_dsbl_mask = 0; /* Start up with DAQ enabled */ + + FS_pid = get_pid (); /* Store our pid */ + StrJoin (FS_name[0], sizeof (FS_name[0]), /* And our task name */ + taskName (FS_pid), ""); + +/* +** Debug hint - set FS_use_sem_tmo to False (== 0) to disable sem time-outs +** during debug sessions. This will stop things falling off. +*/ + FS_sem_tmo = 5 * sysClkRateGet (); /* 5 second time-out by default */ + FS_use_sem_tmo = True; +/* +** Do all the necessary network orientated setup for our slaves to +** make it easier to broadcast commands to them. +*/ +/* +** Get Internet address of the front-end. +*/ + FS_n_slaves = 3; + if ((c_port < 128) || (c_port > 32767)) c_port = 2500; + + status = setup_host (hostM, &FS_rmt_socknam[0], c_port, True); + if (status) FS_slaves[0] = hostM; else FS_slaves[0] = NULL; + status = setup_host (hostO, &FS_rmt_socknam[1], c_port, True); + if (status) FS_slaves[1] = hostO; else FS_slaves[1] = NULL; + status = setup_host (hostU, &FS_rmt_socknam[2], c_port, True); + if (status) FS_slaves[2] = hostU; else FS_slaves[2] = NULL; + + FS_lo_det[0] = 0; + FS_hi_det[0] = FS_lo_det[0] + ndetM - 1; + FS_lo_det[1] = FS_hi_det[0] + 1; + FS_hi_det[1] = FS_lo_det[1] + ndetO - 1; + FS_lo_det[2] = FS_hi_det[1] + 1; + FS_hi_det[2] = FS_lo_det[2] + ndetU - 1; + if (ndetM == 0) FS_slaves[0] = NULL; + if (ndetO == 0) FS_slaves[1] = NULL; + if (ndetU == 0) FS_slaves[2] = NULL; + + for (i = 0; i <= 3; i++) { + FS_slv_active[i] = False; + } +/*============================================================================ +** Clear the process signal mask to let in all signals (actually, on +** PPC VxWorks this seems to cause all signals to get ignored!) and then +** declare action routine for SIGUSR1. Our children signal with SIGUSR1 +** just before they exit in a more or less controlled manner. If the +** child gets deleted from the shell, it will not signal. +*/ + FS_cnt_SIGUSR1 = 0; + + status = sigemptyset (&proc_sigmask); + status = sigprocmask (SIG_SETMASK, &proc_sigmask, NULL); + status = sigemptyset (&sig_action.sa_mask); + sig_action.sa_handler = FS_catch_signal; + sig_action.sa_flags = 0; + + if (sigaction (SIGUSR1, &sig_action, NULL) == -1) { + getErrno (&FS_errno); + perror ("sigaction error:"); + exit (0); + } +/*============================================================================ +** Get a port number to use. If the argument "port" is not +** a valid port number (not in range 128 to 32767), use PORT_BASE. +*/ + FS_port = PORT_BASE; + if ((s_port >= 128) && (s_port < 32768)) FS_port = s_port; +/*============================================================================ +** Create a TCP/IP socket for receiving connection requests, bind it and +** set it to listen. +*/ + FS_cnct_skt = socket (AF_INET, SOCK_STREAM, 0); + if (FS_cnct_skt == -1) { + sprintf (buff, "\n%s -- Cnct-Socket socket error", FS_name[0]); + failInet (buff); + } + setup_host (NULL, &lcl_sockname, FS_port, False); + status = bind (FS_cnct_skt, (struct sockaddr *) &lcl_sockname, + sizeof (lcl_sockname)); + if (status != 0) { + sprintf (buff, "\n%s -- Cnct-Socket bind error", FS_name[0]); + failInet (buff); + } + status = listen (FS_cnct_skt, 5); + if (status != 0) { + sprintf (buff, "\n%s -- Cnct-Socket listen error", FS_name[0]); + failInet (buff); + } +/* +** Clients must now connect to the Connect-port and send either a +** connect, configure, deconfigure, status or exit request. A +** successful configure request must precede any connection request. +** +** When a configure request arrives, the histogram data structures are +** initialised, the histogram filler process (FILLER) is spawned and +** connection requests are enabled. A status reply is sent to the +** client and the connection closed. +** +** When a connection request arrives, a child will be spawned to +** handle the connection. The child will be told which port to use +** and he will release a semaphore when the port is ready. The parent +** then sends the client a reply to tell him which port to use. The +** connection is then closed to await further connections. +*/ + setup_inet_info (FS_host, sizeof (FS_host), /* Find out who we are */ + FS_addr, sizeof (FS_addr)); + printf ("\n%s: Program Ident = \"%s\". Started on %s (%s).\n", + FS_name[0], IDENT, FS_host, FS_addr); + printf ("%s: Protocol Ident = \"%s\"\n", FS_name[0], FS_def_ident); + +#ifndef INST + #error Define the target instrument via the symbol "INST"! +#endif + + if (strcmp (INST, "FOCUS") == 0) { + printf ("%s: Instrument = \"%s\"\n", FS_name[0], "FOCUS"); + }else { + printf ("%s: Instrument is not defined\n", FS_name[0]); + } + + while (keep_going) { + rmt_sockname_len = sizeof (rmt_sockname); + FS_rw_skt = accept (FS_cnct_skt, (struct sockaddr *) &rmt_sockname, + &rmt_sockname_len); + if (FS_rw_skt == -1) { + getErrno (&FS_errno); + sprintf (buff, "\n%s -- Cnct-Socket accept error", FS_name[0]); + failInet (buff); /* No return */ + } + + p_addr = inet_ntoa (rmt_sockname.sin_addr); + cl_port = ntohs (rmt_sockname.sin_port); + printf ("\n%s: Connected to Node %s, Port %d.\n", + FS_name[0], p_addr, cl_port); + + bytes_to_come = sizeof (req_buff); /* Read a command */ + p_addr = (char *) &req_buff; + while (bytes_to_come > 0) { + n_bytes_got = recv (FS_rw_skt, p_addr, bytes_to_come, 0); + if (n_bytes_got <= 0) break; + FS_bytes_got += n_bytes_got; + bytes_to_come -= n_bytes_got; + p_addr += n_bytes_got; + } + + if (FS_cnt_SIGUSR1 > 0) { /* Have any children exited? */ + if (FS_dbg_lev0) printf ("\n%s: Cleaning up children ...", FS_name[0]); + FS_cleanup_children (MAX_CLIENTS, /* Yes, update our database. */ + FS_pids, &FS_cnt_SIGUSR1, FS_dbg_lev0, FS_p_names, ""); + if (FS_dbg_lev0) printf ("\n ... cleanup of children done.\n"); + } + + if (n_bytes_got < 0) { + printf ("\n%s -- R/W-Socket recv error\n", FS_name[0]); + printf ("%s -- Connection to %s will be closed.\n", FS_name[0], + inet_ntoa (rmt_sockname.sin_addr)); + }else if (n_bytes_got == 0) { + printf ("\n%s -- no command received!\n", FS_name[0]); + printf ("%s -- Connection to %s will be closed.\n", FS_name[0], + inet_ntoa (rmt_sockname.sin_addr)); + }else if (bytes_to_come != 0) { + printf ("\n%s -- command packet has wrong number of bytes:" + " %d instead of %d\n", FS_name[0], + n_bytes_got, sizeof (req_buff)); + printf ("%s -- Connection to %s will be closed.\n", FS_name[0], + inet_ntoa (rmt_sockname.sin_addr)); + }else if (ntohl (req_buff.bigend) != 0x12345678) { + printf ("\n%s -- big-endian/little-endian problem!\n" + " Buffer received in non-network byte order!\n", FS_name[0]); + }else { + FS_do_command (0, FS_rw_skt, 4096, &req_buff, &rply_buff); + } + close (FS_rw_skt); FS_rw_skt = 0; + if (ntohl (req_buff.cmnd) == SQHM_EXIT) keep_going = False; + } + close (FS_cnct_skt); FS_cnct_skt = 0; + exit (KER__SUCCESS); + } +/*========================================= End of FOCUS_srv_main.c ========*/