libmoost
/home/mhx/git/github/libmoost/include/moost/nagios/detail/nsca_data_packet.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 // [ricky 7/13/2011 ] Mostly ripped from the nsca_send common.h file
00029 
00030 #ifndef MOOST_NAGIOS_NSCA_CLIENT_NSCA_DATA_PACKET_HPP__
00031 #define MOOST_NAGIOS_NSCA_CLIENT_NSCA_DATA_PACKET_HPP__
00032 
00033 #include <iostream>
00034 #include <string>
00035 #include <stdexcept>
00036 #include <vector>
00037 
00038 #include <boost/lexical_cast.hpp>
00039 
00040 #include "nsca_common.hpp"
00041 
00042 namespace moost { namespace nagios {
00043 
00044    struct nsca_data_packet // MUST be a POD
00045    {
00046       // for some reason the client must randomise the struct (including padding)
00047       // I can only assume this is so identical packets differ when encrypted.
00048       // Seems like overkill to me but, meh -- let's just do it for now.
00049       static void randomize(nsca_data_packet & packet)
00050       {
00051          // [ricky 7/14/2011] Just emulating what the real client does!
00052          srand((int)time(NULL));
00053          for(size_t idx = 0 ; idx < sizeof(packet) ; idx++)
00054          {
00055             ((char *)&packet)[idx]=(int)'0'+(int)(72.0*rand()/(RAND_MAX+1.0));
00056          }
00057       }
00058 
00059       static void zeroize(nsca_data_packet & packet)
00060       {
00061           memset(&packet, 0, sizeof(packet));
00062       }
00063 
00064       boost::int16_t packet_version;
00065       boost::uint32_t crc32_value;
00066       boost::uint32_t timestamp;
00067       boost::int16_t return_code;
00068       char host_name[nsca_const::MAX_HOSTNAME_LENGTH];
00069       char svc_description[nsca_const::MAX_DESCRIPTION_LENGTH];
00070       char plugin_output[nsca_const::MAX_PLUGINOUTPUT_LENGTH];
00071    };
00072 
00073    // Allow us to get a packet from a stream
00074    inline
00075    std::istream & operator >> (std::istream & os, nsca_data_packet & packet)
00076    {
00077       std::vector<std::string> lines;
00078       std::string line;
00079       while(getline(os, line) && lines.size() < 4)
00080       {
00081          lines.push_back(line);
00082       }
00083 
00084       std::string errmsg;
00085       for(int check = 0 ; check >= 0 && !os.bad();)
00086       {
00087          switch(check++)
00088          {
00089          case 0:
00090             if(lines.size() != 4)
00091             {
00092                errmsg = "Payload string is malformed";
00093             }
00094             break;
00095          case 1:
00096             if(lines[0].size() > nsca_const::MAX_HOSTNAME_LENGTH-1)
00097             {
00098                errmsg = "Hostname is too long for NSCA to handle";
00099             }
00100             break;
00101          case 2:
00102             if(lines[1].size() > nsca_const::MAX_DESCRIPTION_LENGTH-1)
00103             {
00104                errmsg = "Service description is too long for NSCA to handle";
00105             }
00106             break;
00107          case 3:
00108             if(lines[3].size() > nsca_const::MAX_PLUGINOUTPUT_LENGTH-1)
00109             {
00110                errmsg = "Servcice description is too long for NSCA to handle";
00111             }
00112             break;
00113          default:
00114             check = -1; // no more checks.
00115             break;
00116          }
00117 
00118          if(!errmsg.empty())
00119          {
00120             // Oops, something's wrong
00121             os.setstate(std::ios::failbit);
00122 
00123             // If the caller is expecting exceptions for this
00124             // stream give them what they asked for.
00125             if((os.exceptions() & std::ios::failbit) == std::ios::failbit)
00126             {
00127                throw std::invalid_argument(errmsg);
00128             }
00129          }
00130       }
00131 
00132       // All good?
00133       if(!os.bad())
00134       {
00135          strcpy(packet.host_name, lines[0].c_str());
00136          strcpy(packet.svc_description, lines[1].c_str());
00137          strcpy(packet.plugin_output, lines[3].c_str());
00138          packet.return_code = boost::lexical_cast<boost::int16_t>(lines[2]);
00139       }
00140 
00141       return os;
00142    }
00143 
00144 }}
00145 
00146 #endif