#define IDENT "1A08" /* ** +--------------------------------------------------------------+ ** | 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]SinqHM_srv_server.c ** ** Author . . . . . . . . . . : D. Maden ** Date of creation . . . . . . : Oct 1996 ** ** Updates: ** 1A01 2-Oct-1996 DM Initial version. ** ** SinqHM_srv_server.c forms a child process of the SINQ Histogram Memory ** process. It does the communication with the client. ** ** To compile this program for VxWorks on PSS123, use: ** ccvx SinqHM_srv_server.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 ** **==================================================================== */ #include #include #include #include #include #include #include #include /* Get the POSIX environment defined .. ** .. see DEC OSF/1 Guide to Realtime Programming */ #include #include #include #include #include /* Get POSIX mem mgmnt definitions. */ #include /* Get POSIX signal definitions. */ #include #include /* Get POSIX wait definitions. */ /* **==================== Global Definitions ===================================== */ #include "SinqHM_def.h" #include "SinqHM_gbl.h" /*============================================================================== Local Routines for SRV ** None */ /*============================================================================== Global Routines for SRV ** */ void SinqHM_server_setup_id () { /* ====================== ** Simply copy some ident information to global variables ** for use by the SQHM_IDENT request. */ StrJoin (Sqhm_serv_ident, sizeof (Sqhm_serv_ident), IDENT, ""); StrJoin (Sqhm_serv_date, sizeof (Sqhm_serv_date), __DATE__, ", "); StrJoin (Sqhm_serv_date, sizeof (Sqhm_serv_date), Sqhm_serv_date, __TIME__); } /*============================================================================== Here beginneth the main code for SinqHM_server ... ** ** Note: There must be NO return from this function. */ int SinqHM_server (int suspend_flag, int index, int pkt_size) { /* ============= ** ** Set up TCP/IP port for operations with client, accept his ** connection and perform services for him. */ int status, status0, status1; int i, is, nbytes, bytes_to_come; char recd[80]; char *p_nxt_byte; int cnct_skt, rw_skt; struct sockaddr_in my_lcl_sockname; struct sockaddr_in my_rmt_sockname; int my_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; port = Port_base + index; /*============================================================================ */ StrJoin (Tsk_name[index], sizeof (Tsk_name[0]), taskName (get_pid ()), ""); if (suspend_flag != 0) { printf ("\n%s: Suspending ..\n", Tsk_name[index]); taskSuspend (0); /* We've been told to suspend ourself, .. ** .. presumably for debug reasons. */ printf ("\n%s: Suspension ended!\n", Tsk_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 = catch_int_signal; sig_action.sa_flags = 0; if (sigaction (SIGINT, &sig_action, NULL) == -1) { getErrno (&My_errno); perror ("sigaction error:"); Child_exit_status[index] = -1; /* Tell our parent we've given up */ is = semGive (Sem_Server); /* Let our parent continue */ exit (KER__BAD_VALUE); } /*============================================================================ ** Create a TCP/IP socket for communication, bind it and listen. */ Child_cnct_skt[index] = 0; cnct_skt = socket (AF_INET, SOCK_STREAM, 0); if (cnct_skt == -1) { perror (StrJoin (recd, sizeof (recd), Tsk_name[index], " -- cnct_skt socket error")); Child_exit_status[index] = -2; /* Tell our parent we've given up */ is = semGive (Sem_Server); /* Let our parent continue */ exit (KER__BAD_VALUE); } status = 1; setsockopt(cnct_skt, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int)); my_lcl_sockname.sin_family = AF_INET; my_lcl_sockname.sin_port = htons (port); my_lcl_sockname.sin_addr.s_addr = 0; status = bind (cnct_skt, (struct sockaddr *) &my_lcl_sockname, sizeof (my_lcl_sockname)); if (status != 0) { close (cnct_skt); perror (StrJoin (recd, sizeof (recd), Tsk_name[index], " -- cnct_skt bind error")); Child_exit_status[index] = -2; /* Tell our parent we've given up */ is = semGive (Sem_Server); /* Let our parent continue */ exit (KER__BAD_VALUE); } status = listen (cnct_skt, 1); if (status != 0) { close (cnct_skt); perror (StrJoin (recd, sizeof (recd), Tsk_name[index], " -- cnct_skt listen error")); Child_exit_status[index] = -3; /* Tell our parent we've given up */ is = semGive (Sem_Server); /* Let our parent continue */ exit (KER__BAD_VALUE); } /*============================================================================ ** 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. */ is = semGive (Sem_Server); if (is != OK) { kill (Parent_pid, SIGUSR1); /* Inform parent that we are in trouble */ printf ("%s -- sem release error\n", Tsk_name[index]); close (cnct_skt); exit (KER__BAD_VALUE); } Child_cnct_skt[index] = cnct_skt; /*============================================================================ ** Ensure that our bit in SinqHM_Dsbl_Mask is clear. */ do_daq (&my_rply_bf, index, DAQ__CLR); /*============================================================================ ** Wait for the client to connect to our port */ my_rmt_sockname_len = sizeof (my_rmt_sockname); rw_skt = accept (cnct_skt, (struct sockaddr *) &my_rmt_sockname, &my_rmt_sockname_len); if (rw_skt == -1) { perror (StrJoin (recd, sizeof (recd), Tsk_name[index], " -- cnct_skt accept error")); close (cnct_skt); Child_cnct_skt[index] = 0; kill (Parent_pid, SIGUSR1); /* Inform parent that we are in trouble */ exit (KER__BAD_VALUE); } Child_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 (rw_skt, p_nxt_byte, bytes_to_come, 0); if (nbytes <= 0) break; Rw_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 = do_command (index, rw_skt, pkt_size, &my_req_bf, &my_rply_bf); if (is == OK) 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. ** Anything else is a fatal error. */ do_daq (&my_rply_bf, index, DAQ__CLR); /* Ensure our inhibit bit is clear */ close (rw_skt); Child_rw_skt[index] = 0; close (cnct_skt); Child_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), Tsk_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", Tsk_name[index]); status = KER__SUCCESS; }else { printf ("\n%s -- rw_skt recv wrong number of bytes: %d\n", Tsk_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", Tsk_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", Tsk_name[index]); status = KER__SUCCESS; }else { /* Unrecognised request received! */ printf ("\n%s -- unrecognised command received: 0x%x\n", Tsk_name[index], ntohl (my_req_bf.cmnd)); status = KER__EXIT_SIGNAL; } kill (Parent_pid, SIGUSR1); /* Inform parent that we are exiting */ exit (status); } /*======================================= End of SinqHM_srv_server.c ========*/