Changeset 224 for Evidence


Ignore:
Timestamp:
06/17/10 09:00:51 (14 years ago)
Author:
ogrimm
Message:
Message severity encoded now using standard DIM structure, other updates
Location:
Evidence
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • Evidence/Bridge.cc

    r221 r224  
    77  thus serialized by DIM and no Mutex is necessary.
    88
    9   Oliver Grimm, May 2010
     9  Remote procedure calls are bridged through their underlying services
     10  and commands.
     11 
     12  Oliver Grimm, June 2010
    1013
    1114\********************************************************************/
     
    2124using namespace std;
    2225
     26
    2327// Class declaration
    2428class Bridge: public DimClient, public EvidenceServer {
    2529
    2630        struct Item {
     31          string Name;
     32          DimCommand *Command;
    2733          DimStampedInfo *DataItem;
    2834          DimService *Service;
     
    3440       
    3541    void infoHandler();
    36         void AddService(string, const char *);
     42    void commandHandler();
     43        void AddService(string, char *, int);
    3744        void RemoveService(string);
    3845   
     
    4249};
    4350
    44 //
    4551// Constructor
    46 //
    4752Bridge::Bridge(char *Name, int Port): EvidenceServer(SERVER_NAME) {
    4853
     
    5459}
    5560
    56 //
     61
    5762// Destructor: Delete all subscriptions and services
    58 //
    5963Bridge::~Bridge() {
    6064
    61   while (List.size() != 0) RemoveService(List[0].DataItem->getName()); 
     65  while (List.size() != 0) RemoveService(List[0].Name); 
    6266  delete ServerList;
    6367}
    6468
    65 //
     69
    6670// Service subscription and repeating
    67 //
    6871void Bridge::infoHandler() {
    6972
     
    8083                RemoveService(string(Token)+"/SERVICE_LIST");
    8184          }
    82           else AddService(string(Token)+"/SERVICE_LIST", "C");
     85          else AddService(string(Token)+"/SERVICE_LIST", (char *) "C", DimSERVICE);
    8386
    8487          // Skip server IP address and process ID
     
    9194  // If service is SERVICE_LIST, scan and subscribe/unsubscribe to services
    9295  if (strstr(I->getName(), "/SERVICE_LIST") != NULL) {
    93         char *Type, *Name = strtok(I->getString(), "+-!|");
     96        char *Format, *Name = strtok(I->getString(), "+-!|");
    9497        while (Name != NULL) {
    95           // Only consider DIM services (not commands and RPCs)
    96       if (((Type = strtok(NULL, "\n")) != NULL) &&
    97                   (strstr(Type, "|CMD") == NULL) && (strstr(Type, "|RPC") == NULL)) {
    98             if (*I->getString() == '-' || *I->getString() == '!') RemoveService(Name);
     98      if ((Format = strtok(NULL, "\n")) != NULL) {
     99            // Check if service added or removed/unavailable
     100            if (*I->getString() == '-' || *I->getString() == '!') {
     101                  if (strstr(Format, "|RPC") != NULL) {
     102                        RemoveService(string(Name)+"/RpcIn");
     103                        RemoveService(string(Name)+"/RpcOut");
     104                  }
     105                  else RemoveService(Name);
     106                }
    99107                else {
    100                   Type[strlen(Type)-1] = '\0'; // Isolate service format
    101                   AddService(Name, Type);
     108                  // Determine type of service
     109                  if (strstr(Format, "|CMD") != NULL) {
     110                        *(strstr(Format, "|CMD")) = '\0';
     111                        AddService(Name, Format, DimCOMMAND);
     112                  }
     113                  else if (strstr(Format, "|RPC") != NULL) {
     114                        *(strstr(Format, "|RPC")) = '\0';
     115                    if (strchr(Format, ',') != NULL) {
     116                          *strchr(Format, ',') = '\0';
     117                          AddService(string(Name)+"/RpcIn", Format, DimCOMMAND);
     118                          AddService(string(Name)+"/RpcOut", Format+strlen(Format)+1, DimSERVICE);
     119                        }
     120                       
     121                  }
     122                  else {
     123                        Format[strlen(Format)-1] = '\0';
     124                        AddService(Name, Format, DimSERVICE);
     125                  }
    102126                }
    103127          }
     
    110134  for (int Service=0; Service<List.size(); Service++) if (I == List[Service].DataItem) {
    111135
    112         // Ignores repeating DIS_DNS services
    113         if (List[Service].Service == NULL) break;
    114 
    115136    // Copy service data
    116137    delete[] List[Service].Data;
     
    125146}
    126147
    127 //
    128 // Add service subscription
    129 //
    130 void Bridge::AddService(string Name, const char *Format) {
     148
     149// Command repeating
     150void Bridge::commandHandler() {
     151 
     152  sendCommandNB(getCommand()->getName(), getCommand()->getData(), getCommand()->getSize());
     153}
     154
     155
     156// Service subscription
     157void Bridge::AddService(string Name, char *Format, int Type) {
     158
     159  // Do not forward  DIS_DNS and History services
     160  if ((Name.find("DIS_DNS/") != string::npos) || (Name.find("History/") != string::npos)) return;
    131161
    132162  // Check if already subscribed to this service
    133163  for (int i=0; i<List.size(); i++) {
    134         if (Name == List[i].DataItem->getName()) return;
    135   }
    136 
    137   // Create subscription and new service to secondary DNS (do not forward DIS_DNS services)
    138   struct Item New;
    139  
    140   New.Data = NULL;
    141   if (Name.find("DIS_DNS/") != string::npos) New.Service = NULL;
    142   else New.Service = new DimService(Name.c_str(), (char *) Format, New.Data, 0);
    143   New.DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
     164        if (Name == List[i].Name) return;
     165  }
     166
     167  // Create subscription and service to secondary DNS or new command
     168  struct Item New = {Name, NULL, NULL, NULL, NULL};
     169
     170  if  (Type == DimSERVICE) { 
     171        New.Service = new DimService(Name.c_str(), (char *) Format, New.Data, 0);
     172        New.DataItem = new DimStampedInfo(Name.c_str(), NO_LINK, this);
     173  }
     174  else if (Type == DimCOMMAND) New.Command = new DimCommand(Name.c_str(), Format, this);
     175
    144176  List.push_back(New);
    145177}
    146178
    147179
    148 //
    149 // Remove service from watch list
    150 //
     180// Remove service from watch list (unused pointer are NULL)
    151181void Bridge::RemoveService(string Name) {
    152182
    153   // Find service index
    154183  vector<struct Item>::iterator E;
    155   for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).DataItem->getName()) {
     184  for (E=List.begin(); E<List.end(); ++E) if (Name == (*E).Name) {
    156185        delete (*E).DataItem;
    157186        delete (*E).Service;
    158187        delete[] (*E).Data;
     188        delete (*E).Command;
     189
    159190        List.erase(E);
    160191  }
     
    162193
    163194
    164 //         
    165195// Main program
    166 //
    167196int main(int argc, char *argv[]) {
    168197
     198  // Check command line argument
    169199  if (argc == 1) {
    170200        printf("Usage: %s <address of primary DNS> [port] (default port %d)\n", argv[0], DEFAULT_PORT);
  • Evidence/Config.cc

    r221 r224  
    7474  // Open configuration file
    7575  if ((File = fopen(Filename, "r")) == NULL) {
    76     Message(FATAL, "Could not open configuration file '%s' (%s)\n", Filename, strerror(errno));
     76    Message(FATAL, "Could not open configuration file '%s' (%s)", Filename, strerror(errno));
    7777  }
    7878
     
    8181    Message(WARN, "Error setting configuration file '%s' to unbuffered mode", Filename);
    8282  }
    83  
     83
    8484  // Create DIM services
    8585  ConfigChanged();
  • Evidence/DColl.cc

    r221 r224  
    9595 
    9696  LogSizeMB = FileSize(LogFile)/1024.0/1024.0;
    97   LogSizeService = new DimService(SERVER_NAME "/LogSizekB", LogSizeMB);
     97  LogSizeService = new DimService(SERVER_NAME "/LogSizeMB", LogSizeMB);
    9898
    9999  DataFilename = new DimService(SERVER_NAME "/CurrentFile", (char *) "");
     
    216216        // Create direcory if not existing (ignore error if already existing)
    217217        char *Dir;
    218         if (asprintf(&Dir, "%s/%d%02d", BaseDir, T->tm_year+1900, T->tm_mon + 1) == -1) {
     218        if (asprintf(&Dir, "%s/%d", BaseDir, T->tm_year+1900) == -1) {
    219219          Message(FATAL, "asprintf() failed, could not create direcory name"); 
    220220        }
  • Evidence/Edd/Edd.cc

    r222 r224  
    9999
    100100// Update widget
    101 void EddLineDisplay::Update(QString Name, int Time, QByteArray Array, QString Format, QString Text) {
     101void EddLineDisplay::Update(QString Name, int Time, QByteArray, QString Format, QString Text) {
    102102
    103103  if (ServiceName != Name) return;
     
    109109    setText("n/a");
    110110    Pal.setColor(QPalette::Base, Qt::lightGray);
    111   }
    112   else {
    113     // Backgound colour determined by last byte
    114     switch (Array[Array.size()]) {
     111        setPalette(Pal);
     112        return;
     113  }
     114
     115  // Message service backgound colour determined by severity
     116  if (Name.endsWith("/Message")) {
     117    switch (Text.section(' ', 0, 0).toInt()) {
    115118      case 0:  Pal.setColor(QPalette::Base, Qt::white); break;
    116119      case 1:  Pal.setColor(QPalette::Base, Qt::yellow); break;
     
    119122      default: break;
    120123    }
    121        
    122         if (Format[0].toUpper() != 'C') Text = Text.section(' ', Index, Index);
    123 
    124         if (!ShowAsTime) setText(Text);
    125         else setText(QDateTime::fromTime_t(Text.toInt()).toString());
    126         setCursorPosition(0);
    127   }
    128  
     124        Text = Text.section(' ', 1);
     125  }     
     126  else if (Format[0].toUpper() != 'C') Text = Text.section(' ', Index, Index);
     127
     128  if (!ShowAsTime) setText(Text);
     129  else setText(QDateTime::fromTime_t(Text.toInt()).toString());
     130
     131  setCursorPosition(0); 
    129132  setPalette(Pal);
    130133}
  • Evidence/Evidence.cc

    r222 r224  
    55  - The server is started with the given name.
    66  - DIM exit and error handlers are implemented.
    7   - The Message service is published (special format, see below).
    8     It can be updated with the Message() method. The text will also be logged.
     7  - A Message service is published with severity encoding. It can be updated
     8    with the Message() method. The text will also be logged.
    99  - If the severity of a Message() call is FATAL, exit() will be called (with
    1010    this severity, the call to Message() is guranteed not to return).
     
    1616    DIMInfo service into text
    1717  - A terminate-handler is installed for catching unhandled C++ exceptions.
    18  
    19   All memory allocated by the non-static methods will be freed by the
     18
     19  Memory allocated by the non-static methods will be freed by the
    2020  class destructor.
    2121 
    22   Oliver Grimm, March 2009
     22  Oliver Grimm, June 2010
    2323 
    2424\********************************************************************/
     
    3737
    3838  // Initialize
    39   Status = NULL;
    40   StdOutText = NULL;
     39  MessageService = NULL;
     40  MessageData = NULL;
    4141  ExitRequest = false;
    4242  ThisServer = this;
     
    5454  // Subscribe to modify service for keeping track of config file changes
    5555  ModifyInfo = new class ConfigUpdate();
    56  
     56
     57  // Message service and initial message
     58  MessageService = new DimService((ServerName+"/Message").c_str(), (char *) "I:1;C", NULL, 0);
     59
     60  string Rev(EVIDENCE_REVISION);
     61  Message(INFO, "Server started (%s, compiled %s %s)", (Rev.substr(1, Rev.size()-3)).c_str(),__DATE__, __TIME__);
     62
    5763  // Start server
    58   string Rev(EVIDENCE_REVISION);
    59   Rev = Rev.substr(1, Rev.size()-3);
    60   snprintf(InitMsg, sizeof(InitMsg), "Server started (%s, compiled %s %s)", Rev.c_str(),__DATE__, __TIME__);
    61  
    62   Status = new DimService((ServerName+"/Message").c_str(), (char *) "C", InitMsg, strlen(InitMsg)+1);
    63   StdOut = new DimService((ServerName+"/Textout").c_str(), (char *) "");
    64 
    6564  start(Name);
    66   addExitHandler(this);
     65  addExitHandler(this); 
    6766}
    6867
     
    7271  Message(INFO, "Server stopped");
    7372 
    74   for (unsigned int i=0; i<ConfigList.size(); i++) {
    75         delete[] ConfigList[i].Value;
    76   }
     73  for (unsigned int i=0; i<ConfigList.size(); i++) delete[] ConfigList[i].Value;
    7774  delete ModifyInfo;
    78  
    79   delete Status;
    80   delete StdOut;
     75  delete MessageService;
     76  delete MessageData;
    8177}
    8278
     
    9086// DIM error handler
    9187void EvidenceServer::errorHandler(int Severity, int Code, char *Text) {   
    92   Message(ERROR, "%s (DIM error code %d, severity %d)\n", Text, Code, Severity);
    93 }
    94 
    95 // Set status of server
    96 //
    97 // The message format is special: after the string-terminating '\0' the Severity
    98 // is given, terminated by another '\0'  The buffer for the DIM service must have
    99 // the same lifetime as the DIM service. If Severity is FATAL, exit() will be invoked.
     88  Message(ERROR, "%s (DIM error code %d, DIM severity %d)\n", Text, Code, Severity);
     89}
     90
     91// Set server message (if Severity is FATAL, exit() will be invoked)
    10092void EvidenceServer::Message(MessageType Severity, const char *Format, ...) {
    10193
    10294  static const char* StateString[] = {"Info", "Warn", "Error", "Fatal"};
    10395  static char ErrorString[] = "vasprintf() failed in Message()";
    104   static char SBuf[STATUS_SIZE];
    105   char TBuf[STATUS_SIZE];
    106   char *Tmp;
     96  char *Text;
    10797 
    10898  // Assemble message from application
    10999  va_list ArgumentPointer;
    110100  va_start(ArgumentPointer, Format);
    111   if (vasprintf(&Tmp, Format, ArgumentPointer) == -1) Tmp = ErrorString;
     101  if (vasprintf(&Text, Format, ArgumentPointer) == -1) {
     102        Text = ErrorString;
     103        Severity = ERROR;
     104  }
    112105  va_end(ArgumentPointer);
    113106
    114   // Create normal string
    115   snprintf(TBuf, sizeof(TBuf), "%s (%s): %s", Status->getName(), StateString[Severity], Tmp);
    116 
    117   // Create string with severity encoding
    118   snprintf(SBuf, sizeof(SBuf), "%s*", Tmp);
    119   SBuf[strlen(SBuf)-1] = '\0';          // new string terminiation replaces '*'
    120   SBuf[strlen(SBuf)+1] = Severity;      // Severity after new string termination
    121 
    122   if (Tmp != ErrorString) free(Tmp);
     107  // Generate new Message structure and free text
     108  struct Message *NewMsg = (struct Message *) new char [sizeof(struct Message)+strlen(Text)+1];
     109  NewMsg->Severity = Severity;
     110  strcpy(NewMsg->Text, Text);
     111  if (Text != ErrorString) free(Text);
    123112 
    124113  // Send message to console and log file
    125   printf("%s\n", TBuf);
    126   DimClient::sendCommandNB("DColl/Log", TBuf);
    127 
    128   // Update DIM status service (including severity encoding)
    129   if (Status != NULL) Status->updateService(SBuf, strlen(SBuf)+2);
    130 
    131   // Terminate if message type is fatal
     114  printf("%s (%s): %s\n", MessageService->getName(), StateString[Severity], NewMsg->Text);
     115  SendToLog("%s (%s): %s", MessageService->getName(), StateString[Severity], NewMsg->Text);
     116
     117  // Update DIM message service, then delete old message
     118  if (MessageService != NULL) {
     119        MessageService->updateService(NewMsg, sizeof(struct Message)+strlen(NewMsg->Text)+1);
     120  }
     121  delete MessageData;
     122  MessageData = NewMsg;
     123
     124  // Terminate if severity if FATAL 
    132125  if (Severity == FATAL) exit(EXIT_FAILURE);
    133126}
    134127
    135 // Set text of StdOut service
    136 void EvidenceServer::SetStdOut(char *Text) {
    137 
    138   // Copy text to permanent buffer
    139   char *Tmp = new char[strlen(Text)+1];
    140   strcpy(Tmp, Text);
    141   StdOut->updateService(Tmp);
    142 
    143   // Delete old buffer and save new buffer pointer
    144   delete[] StdOutText;
    145   StdOutText = Tmp;   
    146 }
     128
     129// Set to central logging server with non-blocking command (may be used in DIM handler)
     130void EvidenceServer::SendToLog(const char *Format, ...) {
     131
     132  char *Buffer;
     133  int Ret;
     134
     135  // Evaluate variable argument list
     136  va_list ArgumentPointer;
     137  va_start(ArgumentPointer, Format);
     138  Ret = vasprintf(&Buffer, Format, ArgumentPointer);
     139  va_end(ArgumentPointer);
     140
     141  // Send to logger
     142  if (Ret != -1) {
     143        DimClient::sendCommandNB("DColl/Log", Buffer);
     144        free (Buffer);
     145  }
     146  else Message(ERROR, "Could not create logging text in SendToLog(), vasprintf() failed");
     147}
     148
    147149
    148150// Get configuration data
     
    191193
    192194  // Create new entry in item list, allocate memory and copy data to this memory
     195  ConfigList[ItemNo].Name = Item;
    193196  ConfigList[ItemNo].Value = new char [strlen(Result)+1];
    194   ConfigList[ItemNo].Name = Item;
    195197  strcpy(ConfigList[ItemNo].Value, Result);
    196198  ConfigList[ItemNo].Time = ModifyInfo->LastModifyTime;
     
    208210  static bool Called = false;
    209211
     212  // At first invocation just request exit
    210213  if (!Called) {
    211214        Called = true;
     
    226229
    227230  if (Terminating) {
    228         snprintf(Msg, sizeof(Msg), "%s: Terminate() called recursively, calling abort()", ThisServer->Status->getName());
     231        snprintf(Msg, sizeof(Msg), "%s: Terminate() called recursively, calling abort()", ThisServer->MessageService->getName());
    229232        printf("%s\n", Msg);
    230233        DimClient::sendCommandNB("DColl/Log", Msg);
     
    259262
    260263// Translates DIMInfo to string (memory has to be freed by caller)
    261 // Static method: it cannot report memory allocation errors via Message()
     264// Static method, cannot report memory allocation errors via Message() but returns NULL
    262265char *EvidenceServer::ToString(DimInfo *Item) {
    263266
     
    266269  // Safety check
    267270  if (Item->getSize() < 1) return NULL;
     271
     272  // Message structure format handled
     273  if (strcmp(Item->getFormat(), "I:1;C") == 0) {
     274        struct Message *Msg = (struct Message *) Item->getData();
     275        if (asprintf(&Text, "%d %s", Msg->Severity, Msg->Text) == -1) return NULL;
     276        else return Text;
     277  }
    268278 
    269279  // Structure: print hex representation (3 characters per byte) 
  • Evidence/Evidence.h

    r222 r224  
    1919// Class declation of Evidence server
    2020class EvidenceServer: public DimServer {
     21
    2122  private:
    2223        // This class will contain in LastModifyTime always
    2324        // the unix time of the last config file update
    24         class ConfigUpdate: public DimClient {
    25           DimInfo *ModifyInfo;
     25        class ConfigUpdate: public DimClient, public DimRpcInfo {
     26          DimInfo *ModifyInfo;
    2627         
    2728          public:
    28             ConfigUpdate() {
     29            ConfigUpdate(): DimRpcInfo("ConfigRequest", NO_LINK) {
    2930              LastModifyTime = 0;
    3031                  ModifyInfo = new DimInfo("Config/ModifyTime", NO_LINK, this);
     
    3334                  delete ModifyInfo;
    3435                }
     36            void Request(const char *What){
     37              setData((char *) What);
     38            }
     39
    3540            void infoHandler(){
    3641              if (EvidenceServer::ServiceOK(getInfo())) LastModifyTime = getInfo()->getInt();
    3742            }
     43
     44            void rpcInfoHandler(){
     45                  //printf("Received %s\n", getString());
     46            }
     47
    3848                int LastModifyTime;
    3949        };
     50
     51  private:
    4052
    4153        struct ConfigItem {
     
    4658        std::vector<struct ConfigItem> ConfigList;
    4759
     60        struct Message {
     61      int Severity;
     62          char Text[];
     63        };
     64
    4865        std::string ServerName;
    49     DimService *Status, *StdOut;
     66    DimService *MessageService;
     67        struct Message *MessageData;
    5068        class ConfigUpdate *ModifyInfo;
    51        
    52         char InitMsg[STATUS_SIZE];
    53         int LastModifyTime;
    54         char *StdOutText;
    5569       
    5670    static void SignalHandler(int); // static for signal()
     
    6680
    6781        void Message(MessageType, const char *, ...);
    68         void SetStdOut(char *);
     82        void SendToLog(const char *, ...);
    6983        char* GetConfig(std::string, const char * = NULL);
    7084        static char* ToString(DimInfo *);
  • Evidence/History.cc

    r222 r224  
    259259  // Set minimum required change if given in configuratrion
    260260  char *Pnt = strstr(Change, Name.c_str());
     261
    261262  if (Pnt != NULL && *(Pnt+Name.size()) == ':') New.MinAbsChange = atof(Pnt+Name.size()+1);
    262263  else New.MinAbsChange = 0;
  • Evidence/readme.txt

    r222 r224  
    2929                        FATAL. The erroneous expression is ignored in the following.
    303025/5/2010       Service history remains available if service itself become unavailable. If not
    31                         yet in memory, reading from history file is tried. Improved error handling of
     31                        yet in memory, reading from file is tried. Improved error handling of
    3232                        history files.
    333328/5/2010       Changed name of 'State' service to 'Message' to better reflect its functionality.
     
    353530/5/2010       Created Bridge server that repeats services from one DNS to another.
    3636                        Service quality now also written to slow data file.
    37 31/5/2010       Configuration file format now follows semi-standard INI format.
     3731/5/2010       Configuration file format follows semi-standard INI format.
    38387/6/2010        Separated History service from DColl. History format changed, now includes
    3939                        service format (allows history access also when service is unavailable).
     4011/6/2010       Bridge does not forward history service
     4117/6/2010       Added SendToLog() method. Changed severity encoding of Message service to
     42                        use standard DIM structure of format "I:1;C"
    4043
    4144
Note: See TracChangeset for help on using the changeset viewer.