1
0
Files
2022-09-29 17:59:04 +03:00

663 lines
21 KiB
C++

/*
* msg.c++ - the class that implements event messaging between clients and the
* event daemon
*
* This is ONLY place that understands the communication protocols and data
* formats being used. Everyone else deals with the EV_event class. The only
* user of the msg classes is the EV_handler class.
*
* Note any changes to message definition of the communications between client
* and server require changes in FIVE places:
*
* the file nveventd_types (for ToolTalk type compiler)
* the include files tteventdOps.h and tteventdOpStrs.h
* and here in the two functions EV_msg::send and EV_msg::receiveEnd
*
* Note also that the send and receive sides are split into client and server
* versions of the classes.
*
* $Revision: 1.11 $
*/
/*
* Copyright 1992 Silicon Graphics, Inc. All rights reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libc.h>
#include <sys/time.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <tt_c.h>
}
#include <osfcn.h>
#include "event.h"
#include "ttEventdOpStrs.h"
#include "msg.h"
#define D_PRINTF(stuff) if (EV_debugging) fprintf stuff;
extern int EV_debugging; // space allocated in event.c++
/*
* All the initalization is for tooltalk communications
*/
EV_msg::EV_msg(void) {
tterr = TT_OK;
ttop = NULL; // the tooltalk operation
ttreplymark = 0; // pointer to tt data for the NV_Register request/reply
mark = 0; // pointer to the tt data for incoming notice
opnum = 0; // operation number - goes with the op which is a string
m, msgin = 0; // pointers to the tt message.
}
/*
* close the tooltalk communications
*/
EV_msg::~EV_msg(void) {
tt_close();
}
/*
* open TT communications. Common code called by client and server opens.
* Currently open forces all clients to use the same/default ttsession that
* is running on the local host and defined by the localhost and X display
* ":0". In the future clients may be allowed to specify a session to join.
*
* To avoid the annoying "sh: ttsession not found" message on systems that
* have not installed tooltalk, open checks for the package. This is only
* a problem in 4.0.5 and less releases as tooltalk will be bundled with the
* OS with the next major release of Irix (4.1/5.0 whatever it is called).
*/
int
EV_msg::open (void /* XXXX session */) {
#define X_DISPLAY ":0"
#define TT_HOME_DIR "/usr/ToolTalk"
#define TT_SESSION_EXEC "/usr/sbin/ttsession"
char *my_session;
char *xhost = new char[MAXHOSTNAMELEN + (sizeof X_DISPLAY) + 1];
struct stat statbuf;
/* check to see if ToolTalk is installed. This is to avoid those
* nasty sh: ttsession not found messages from the tt_open call.
* Note the check requires both the ToolTalk directory structure
* and ttsession to be in a known place.
*/
if ((stat(TT_HOME_DIR, &statbuf) == -1) ||
(stat(TT_SESSION_EXEC, &statbuf) == -1)) {
return (-1);
}
if (gethostname( xhost, MAXHOSTNAMELEN) != 0) {
perror("EV_msg::open: gethostname");
}
else {
strcat(xhost, X_DISPLAY);
}
my_session = tt_X_session(xhost);
if ((ttstatus = tt_ptr_error(my_session)) != TT_OK) {
fprintf(stderr, "EV_msg::open: tt_X_session: %s\n",
tt_status_message(ttstatus));
}
else {
D_PRINTF((stderr, "EV_msg::open: using ttsession %s\n", my_session));
}
ttstatus = tt_default_session_set(my_session);
D_PRINTF((stderr, "EV_msg::open: tt_default_session_set: %s\n",
tt_status_message(ttstatus)));
ttpid = tt_open();
ttfd = tt_fd();
return (EV_OK); // can always do this. Subsequent functions handle errors
}
/* EV_msg::send
* Send an event via tooltalk.
*
* Note that the argument types, count, and order must be identical to those
* used in EV_msg::receiveEnd AND with the nveventd_types file which defines
* messages to tooltalk. Also the ttEventdOps.h and ttEventdOpStrs.h files must
* be kept in sync with these functions.
* Changes must be kept in sync in all five places.
*
* This is common code used by both the client and server side.
*/
int
EV_msg::send(EV_event *ep, char *noSends) {
int retval = EV_OK;
D_PRINTF((stderr, "EV_msg::send ENTRY with event:\n"));
if (EV_debugging) ep->dump(stderr);
/*
* XXXXX The highlight events will be added
*/
int argc = 0;
//first set the common data shared by all events
tt_message_iarg_add(m, TT_IN, "int", (int) ep->evType); argc++;
tt_message_iarg_add(m, TT_IN, "int", (int) ep->timeSent); argc++;
tt_message_iarg_add(m, TT_IN, "int", (int) ep->alarmLevel); argc++;
tt_message_arg_add(m, TT_IN, "string", ep->getSrcApp()); argc++;
tt_message_iarg_add(m, TT_IN, "int", (int) ep->pid); argc++;
tt_message_arg_add(m, TT_IN, "string", ep->getUserName()); argc++;
tt_message_iarg_add (m, TT_IN, "int", (int) ep->uid);
tt_message_arg_add(m, TT_IN, "string", ep->srcHost.name); argc++;
tt_message_arg_add(m, TT_IN, "string", ep->srcHost.addr); argc++;
tt_message_arg_add(m, TT_IN, "string", ep->filter); argc++;
tt_message_arg_add(m, TT_IN, "string", ep->interface.name); argc++;
tt_message_arg_add(m, TT_IN, "string", ep->interface.addr); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->otherData); argc++;
// now set event specific data
switch (ep->evType) {
case NV_REGISTER:
// On the request side, this is NULL place holder. On a response
// there will be data.
tt_message_arg_add (m, TT_INOUT, "string", NULL); argc++;
break;
case NV_NEW_NODE:
tt_message_arg_add (m, TT_IN, "string", ep->node.name); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->node.addr); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->node.MACAddr); argc++;
break;
case NV_NEW_NET:
tt_message_arg_add (m, TT_IN, "string", ep->net.name); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->net.addr); argc++;
break;
case NV_NEW_PROTO:
tt_message_arg_add (m, TT_IN, "string", ep->protocol); argc++;
break;
case NV_CONVERSE_START:
case NV_CONVERSE_STOP:
tt_message_arg_add (m, TT_IN, "string", ep->pair1.name); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->pair1.addr); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->pair1.MACAddr); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->pair2.name); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->pair2.addr); argc++;
tt_message_arg_add (m, TT_IN, "string", ep->pair2.MACAddr); argc++;
tt_message_iarg_add (m, TT_IN, "int", (int) ep->converseBytes); argc++;
tt_message_iarg_add (m, TT_IN, "int", (int) ep->conversePkts); argc++;
break;
case NV_RATE_THRESH_HI_MET:
case NV_RATE_THRESH_HI_UN_MET:
case NV_RATE_THRESH_LO_MET:
case NV_RATE_THRESH_LO_UN_MET:
tt_message_iarg_add (m, TT_IN, "int", (int) ep->base); argc++;
tt_message_iarg_add (m, TT_IN, "int", (int) ep->rate); argc++;
tt_message_iarg_add (m, TT_IN, "int", (int) ep->thresholdRate); argc++;
tt_message_iarg_add (m, TT_IN, "int", (int) ep->baseRate); argc++;
break;
case NV_NEW_TOPN:
{
int n = 0;
while (ep->topNList[n]) {
tt_message_arg_add (m, TT_IN, "string", ep->topNList[n]);
argc++;
}
}
break;
}
D_PRINTF( (stderr, "EV_msg::send sending event %d\n", ep->evType));
// ep->dump();
ttstatus = tt_message_send(m);
if (tt_is_err(ttstatus)) {
D_PRINTF( (stderr, "EV_msg::send tt_message_send: %s\n",
tt_status_message(tterr)));
retval = EV_MSG_ERR_SEND;
}
return (retval);
}
/*
* receiveStart is the common code to begin a receive by
* called by both client and server classes.
*/
int
EV_msg::receiveStart (void) {
D_PRINTF((stderr, "EV_msg::receiveStart ENTERED\n"));
mark = tt_mark(); // to later tell tooltalk the beginning of memory to free
msgin = tt_message_receive(); // get the message from tooltalk
if (!msgin) {
D_PRINTF((stderr, "EV_msg::receive: no message on active descriptor\n"));
return (EV_MSG_ERR_RECEIVE);
}
/*
if (ttstatus = tt_ptr_error(msgin) !=TT_OK) {
D_PRINTF((stderr, "EV_msg::receive: tt_message_receive: %s\n",
tt_status_message(ttstatus)));
return (ttstatus);
}
opnum = tt_message_opnum (msgin);
if (ttstatus = tt_int_error(opnum) != TT_OK) {
D_PRINTF( (stderr, "EV_msg:receive tt_message_opnum: %s\n",
tt_status_message(ttstatus)));
return (ttstatus);
}
*/ return (EV_OK);
}
/*
* receiveEnd is called to actually get the data by both the client and
* server classes.
*/
int
EV_msg::receiveEnd (EV_event *ep) {
int argc; // count of arguments in the message
int nargs = 0; // which argument being processed
argc = tt_message_args_count(msgin);
D_PRINTF( (stderr, "EV_msg::receive ttmsg %d, %s\n",
opnum, tt_message_op(msgin)));
// first get the data common to all events
tt_message_arg_ival(msgin, nargs, (int *) &ep->evType); nargs++;
tt_message_arg_ival(msgin, nargs, (int *) &ep->timeSent); nargs++;
tt_message_arg_ival(msgin, nargs, (int *) &ep->alarmLevel); nargs++;
ep->srcApp = strdup (tt_message_arg_val(msgin, nargs)); nargs++;
tt_message_arg_ival (msgin, nargs, (int *) &ep->pid); nargs++;
ep->userName = strdup (tt_message_arg_val(msgin, nargs)); nargs++;
tt_message_arg_ival (msgin, nargs, (int *) &ep->uid); nargs++;
ep->srcHost.setName (tt_message_arg_val(msgin, nargs)); nargs++;
ep->srcHost.setAddr (tt_message_arg_val(msgin, nargs)); nargs++;
ep->setFilter (tt_message_arg_val(msgin, nargs )); nargs++;
ep->setInterfaceName (tt_message_arg_val(msgin, nargs)); nargs++;
ep->setInterfaceAddr (tt_message_arg_val(msgin, nargs)); nargs++;
ep->setOtherData (tt_message_arg_val (msgin, nargs)); nargs++;
// now get the event specific data
switch (opnum) {
case NV_EV_DETECT_NODE:
ep->objType = OBJ_NODE;
ep->setNodeName (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setNodeAddr (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setNodeMACAddr (tt_message_arg_val (msgin, nargs)); nargs++;
break;
case NV_EV_DETECT_NET:
ep->objType = OBJ_NET;
ep->setNetName (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setNetAddr (tt_message_arg_val (msgin, nargs)); nargs++;
break;
case NV_EV_DETECT_PROTO:
ep->objType = OBJ_PROTO;
ep->protocol = tt_message_arg_val (msgin, nargs); nargs++;
break;
case NV_EV_DETECT_CONV:
ep->objType = OBJ_CONVERSE;
ep->setEndPt1Name (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setEndPt1Addr (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setEndPt1MACAddr (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setEndPt2Name (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setEndPt2Addr (tt_message_arg_val (msgin, nargs)); nargs++;
ep->setEndPt2MACAddr (tt_message_arg_val (msgin, nargs)); nargs++;
tt_message_arg_ival (msgin, nargs, (int *) &ep->converseBytes); nargs++;
tt_message_arg_ival (msgin, nargs, (int *) &ep->conversePkts); nargs++;
break;
case NV_EV_RATE_RPT:
{
int irate = 0, ithresh = 0; int ibofrate = 0;
tt_message_arg_ival (msgin, nargs, (int *) &ep->base); nargs++;
tt_message_arg_ival (msgin, nargs, &irate); nargs++;
ep->rate = irate;
tt_message_arg_ival (msgin, nargs, &ithresh); nargs++;
ep->thresholdRate = ithresh;
tt_message_arg_ival (msgin, nargs, &ibofrate); nargs++;
ep->baseRate = ibofrate;
}
break;
case NV_EV_TOPN_RPT:
{
int n = 0;
D_PRINTF ((stderr, "EV_msg::receive got topN list.\n"));
while (0/*XXXX how do I look at a value?*/) {
ep->topNList[n] = strdup(tt_message_arg_val (msgin, nargs));
nargs++;
}
}
break;
}
return (EV_OK);
}
/*
* Client open is straighforward. Just join the tootalk session and return
* a file descriptor to the user.
*/
int
EV_clnt_msg::open(void) {
EV_msg::open();
ttstatus = tt_session_join(tt_default_session());
if (tt_is_err(ttstatus)) {
D_PRINTF((stderr, "EV_msg::open tt_session_join: %s\n", tt_status_message(ttstatus)));
ttfd = -1;
}
return (EV_msg::ttfd);
}
/*
* The server open. It is the one that declares itself to
* ToolTalk as a handler of netvis event messages.
*/
int
EV_srvr_msg::open(void) {
ttreplymark = 0;
EV_msg::open();
//declare ptype etc.
ttstatus = tt_ptype_declare("SGI_NV_event");
if (tt_is_err(ttstatus)) {
D_PRINTF((stderr, "EV_msg::open tt_ptype_declare: %s\n",
tt_status_message (ttstatus)));
ttfd = -1;
}
ttstatus = tt_session_join(tt_default_session());
if (tt_is_err(ttstatus)) {
D_PRINTF((stderr, "EV_msg::open tt_session_join: %s\n", tt_status_message(ttstatus)));
ttfd = -1;
}
return (EV_msg::ttfd);
}
/*
* client send -- the client send must determine whether it is sending a
* notification or a request. This is based on the event being
* sent. EV_handler will send the NV_Register event on behalf
* of the user and this is treated as a request because the
* reply with the no sends list should come back.
* Additionally, if it is a request, do not destroy the msg
* until the reply comes back. (I'm not sure why this has to
* be handled this way, but the TT guru says so.
*/
int
EV_clnt_msg::send(EV_event *ep, char *noSends) {
int retval;
/*
* Must do this before calling tooltalk message create routines because they
* require the operation to be passed to them.
*/
switch (ep->evType) {
case NV_REGISTER:
ttop=evdOpStrs[NV_EV_REGISTER];
break;
case NV_STARTUP:
case NV_SHUTDOWN:
case NV_START_SNOOP:
case NV_STOP_SNOOP:
case NV_OTHER:
ttop = evdOpStrs[NV_EV_START_STOP_SNOOP];
break;
case NV_NEW_NODE:
ttop = evdOpStrs[NV_EV_DETECT_NODE];
break;
case NV_NEW_NET:
ttop =evdOpStrs[NV_EV_DETECT_NET];
break;
case NV_NEW_PROTO:
ttop = evdOpStrs[NV_EV_DETECT_PROTO];
break;
case NV_CONVERSE_START:
case NV_CONVERSE_STOP:
ttop = evdOpStrs[NV_EV_DETECT_CONV];
break;
case NV_RATE_THRESH_HI_MET:
case NV_RATE_THRESH_HI_UN_MET:
case NV_RATE_THRESH_LO_MET:
case NV_RATE_THRESH_LO_UN_MET:
ttop =evdOpStrs[NV_EV_RATE_RPT];
break;
case NV_NEW_TOPN:
ttop = evdOpStrs[NV_EV_TOPN_RPT];
break;
}
if (ep->evType == NV_REGISTER) {
m = tt_prequest_create (TT_SESSION, ttop);
}
else {
// this is a general event notification
m = tt_pnotice_create(TT_SESSION, ttop );
}
if ((ttstatus = (enum tt_status) tt_ptr_error(m)) != TT_OK) {
D_PRINTF((stderr, "EV_msg::send tt message create: %s\n",
tt_status_message(ttstatus)));
retval = -1;
}
retval = EV_msg::send(ep, NULL);
// can destroy it, no reply is coming
if (ep->evType != NV_REGISTER)
tt_message_destroy(m);
return (retval);
}
/*
* This routine currently is called by the server only for the response to
* the NV_Register message. However, it will be used for forwarding events
* in a future release. Since it is replying, it use tt_message_reply rather
* than tt_message_send. Once the reply is done, the original incoming request
* data may be destroyed.
*/
int
EV_srvr_msg::send(EV_event *ep, char *noSends) {
int retval;
if (ep->evType == NV_REGISTER) {
if (!noSends) {
D_PRINTF( (stderr,
"EV_msg::send should have no noSendList passed\n"));
}
// set the argument for noSends, the others are returned as is
tt_message_arg_val_set (msgin, TT_NOSEND_ARG_NUM, noSends);
D_PRINTF((stderr, "EV_msg::send Sending reply\n"));
if ((tterr = tt_message_reply(msgin)) != TT_OK) {
D_PRINTF( (stderr, "EV_msg::send reply error %s\n",
tt_status_message (tterr)));
retval = -1;
}
else {
retval = EV_OK;
}
tt_release(ttreplymark);
ttreplymark = 0;
tt_message_destroy (msgin);
}
else {
switch (ep->evType) {
case NV_REGISTER:
ttop=evdOpStrs[NV_EV_REGISTER];
break;
case NV_STARTUP:
case NV_SHUTDOWN:
case NV_START_SNOOP:
case NV_STOP_SNOOP:
case NV_OTHER:
ttop = evdOpStrs[NV_EV_START_STOP_SNOOP];
break;
case NV_NEW_NODE:
ttop = evdOpStrs[NV_EV_DETECT_NODE];
break;
case NV_NEW_NET:
ttop =evdOpStrs[NV_EV_DETECT_NET];
break;
case NV_NEW_PROTO:
ttop = evdOpStrs[NV_EV_DETECT_PROTO];
break;
case NV_CONVERSE_START:
case NV_CONVERSE_STOP:
ttop = evdOpStrs[NV_EV_DETECT_CONV];
break;
case NV_RATE_THRESH_HI_MET:
case NV_RATE_THRESH_HI_UN_MET:
case NV_RATE_THRESH_LO_MET:
case NV_RATE_THRESH_LO_UN_MET:
ttop =evdOpStrs[NV_EV_RATE_RPT];
break;
case NV_NEW_TOPN:
ttop = evdOpStrs[NV_EV_TOPN_RPT];
break;
}
m = tt_pnotice_create(TT_SESSION, ttop );
retval = EV_msg::send(ep, NULL);
tt_message_destroy (m);
}
return(retval);
}
/*
* client receive -- receive a message for a client
*
* If this message is the reply to register request, it has (potentially)
* a list of events not to send. So capture them. Called by EV_handler::receive
*/
int
EV_clnt_msg::recv(EV_event *ep, char *noSends) {
char * op;
EV_stat retval = -1;
Tt_state ttstate;
if ((retval = EV_msg::receiveStart()) != EV_OK) return (retval);
ttstate = tt_message_state(msgin);
D_PRINTF((stderr, "EV_clnt_msg::recv TT req is in state %d\n", ttstate));
switch (ttstate) {
case TT_STARTED:
case TT_CREATED:
case TT_QUEUED:
case TT_SENT:
D_PRINTF((stderr,"EV_clnt_msg::recv tt req still being processed\n"));
break;
case TT_FAILED:
D_PRINTF((stderr, "EV_cln_msg::recv TT req failed\n"));
break;
case TT_REJECTED:
D_PRINTF((stderr, "EV_cln_msg::recv TT req rejected\n"));
break;
case TT_STATE_LAST:
D_PRINTF((stderr, "EV_clnt_msg::recv unknown ttstatus\n"));
break;
case TT_HANDLED:
D_PRINTF((stderr,"EV_clnt_msg::recv tt req handled\n"));
op = tt_message_op (msgin);
if ((ttstatus = tt_ptr_error(op)) != TT_OK) {
D_PRINTF( (stderr, "EV_clnt_msg:recv tt_message_opnum: %s\n",
tt_status_message(ttstatus)));
return (ttstatus);
}
if (strcmp(op, evdOpStrs[NV_EV_REGISTER]) == 0) {
if (noSends) {
char *ttPtr = NULL, *sndP = NULL;
int noSendCnt = 0;
ttPtr = sndP = tt_message_arg_val(msgin, TT_NOSEND_ARG_NUM);
// only events not to send are in this message. Use them as
// an index to set the noSend value to true for that event.
while (ttPtr && *sndP) {
noSends[*sndP++] = 1;
noSendCnt++;
}
D_PRINTF((stderr, "EV_clnt_msg::recv noSendCnt %d\n",
noSendCnt));
if (EV_debugging) {
for (int c = 0; c < NV_MAX_EVENT; c++) {
if (noSends[c] != 0) {
D_PRINTF ((stderr,
"\tEvent %d will not be sent\n",
c));
}
}
}
}
else {
D_PRINTF ((stderr, "EV_clnt_msg::recv: requires noSendList\n"));
}
}
else {
EV_msg::receiveEnd(ep);
}
D_PRINTF((stderr, "EV_clnt_msg::recv destroying TT msg %s\n",
tt_message_op(msgin)));
tterr = tt_message_destroy(msgin);
tt_release (mark);
retval = EV_OK;
break;
}
return(retval);
}
/*
* server receive - to handle message coming to the server
*
* Note that the Register message is not destroyed and the data is not released.
* It will be after the reply.
*/
int
EV_srvr_msg::recv(EV_event *ep, char *noSends) {
EV_msg::receiveStart();
opnum = tt_message_opnum (msgin);
if ((ttstatus = tt_int_error(opnum)) != TT_OK) {
D_PRINTF( (stderr, "EV_msg:receive tt_message_opnum: %s\n",
tt_status_message(ttstatus)));
return (ttstatus);
}
if (opnum == NV_EV_REGISTER) {
ttreplymark = mark;
}
EV_msg::receiveEnd(ep);
if (opnum != NV_EV_REGISTER) {
D_PRINTF((stderr, "EV_srvr_msg::recv destroying TT msg %s\n",
tt_message_op(msgin)));
tterr = tt_message_destroy(msgin);
tt_release (mark);
return(/*XXXX*/ TT_OK);
}
}