libmoost
/home/mhx/git/github/libmoost/include/moost/nagios/nsca_client.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_NAGIOS_NSCA_CLIENT_HPP__
00029 #define MOOST_NAGIOS_NSCA_CLIENT_HPP__
00030 
00031 #include <string>
00032 #include <sstream>
00033 #include <stdexcept>
00034 #include <ctime>
00035 #include <boost/asio.hpp>
00036 #include <boost/thread.hpp>
00037 #include <boost/lexical_cast.hpp>
00038 #include <boost/shared_ptr.hpp>
00039 #include "detail/nsca_init_packet.hpp"
00040 #include "detail/nsca_data_packet.hpp"
00041 #include "detail/nsca_config.hpp"
00042 #include "detail/nsca_crc32.hpp"
00043 #include "detail/nsca_crypto.hpp"
00044 #include "detail/nsca_enctype.hpp"
00045 #include "detail/nsca_encpass.hpp"
00046 
00047 namespace moost { namespace nagios {
00048 
00049    class nsca_client
00050    {
00051    public:
00052       // nsca service states
00053       struct service_state {
00054          enum type {
00055             OK,
00056             WARNING,
00057             CRITICAL,
00058             UNKNOWN
00059          };
00060       };
00061 
00062       nsca_client(nsca_config const & cfg)
00063          : cfg_(new nsca_config(cfg))
00064       {
00065       }
00066 
00067       nsca_client(boost::shared_ptr<nsca_config> cfg)
00068          : cfg_(cfg)
00069       {
00070       }
00071 
00072       // Payload format
00073       // "{HOSTNAME}\n{SERVICEDESC}\n{SERVICESTATEID}\n{PLUGINGOUTPUT}"
00074       void send(std::string payload) const
00075       {
00076          nsca_data_packet send_packet;
00077          init_packet(send_packet);
00078 
00079          std::istringstream ss(payload);
00080          ss.exceptions(std::ios::failbit); // simplify life.
00081          ss >> send_packet;
00082 
00083          send(send_packet);
00084       }
00085 
00086       void send(
00087          std::string hostname,
00088          std::string svc_description,
00089          boost::int16_t return_code,
00090          std::string plugin_output) const
00091       {
00092          std::stringstream ss;
00093 
00094          ss
00095             << hostname << "\n"
00096             << svc_description << "\n"
00097             << return_code << "\n"
00098             << plugin_output << "\n";
00099 
00100          ss.exceptions(std::ios::badbit); // simplify life.
00101 
00102          nsca_data_packet send_packet;
00103          init_packet(send_packet);
00104          ss >> send_packet;
00105 
00106          send(send_packet);
00107       }
00108 
00109    private:
00110       typedef boost::shared_ptr<nsca_crypto> crypto_ptr;
00111 
00112       typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
00113 
00114       void init_packet(nsca_data_packet & send_packet) const
00115       {
00116          nsca_data_packet::randomize(send_packet);
00117       }
00118 
00119       // create a connection to the nsca server
00120       socket_ptr connect(boost::asio::io_service & io_service) const
00121       {
00122          using namespace boost::asio::ip;
00123 
00124          tcp::resolver resolver(io_service);
00125          tcp::resolver::query query(tcp::v4(), cfg_->nsca_svr_host.c_str(),
00126             cfg_->nsca_svr_port.c_str());
00127          tcp::resolver::iterator iterator = resolver.resolve(query);
00128 
00129          socket_ptr psock(new tcp::socket(io_service));
00130          psock->connect(*iterator);
00131 
00132          setsockopt(psock->native(), SOL_SOCKET, SO_RCVTIMEO,
00133             reinterpret_cast<char const *>(&cfg_->recv_timeout), sizeof(cfg_->recv_timeout));
00134 
00135          setsockopt(psock->native(), SOL_SOCKET, SO_SNDTIMEO,
00136             reinterpret_cast<char const *>(&cfg_->send_timeout), sizeof(cfg_->send_timeout));
00137 
00138          return psock;
00139       }
00140 
00141       // recv the server initialisation packet from the socket
00142       void recv(socket_ptr psock, nsca_init_packet & packet) const
00143       {
00144          if(boost::asio::read(*psock, boost::asio::buffer(&packet, sizeof(packet))) != sizeof(packet))
00145          {
00146             throw std::runtime_error("failed to recv packet from server");
00147          }
00148 
00149          using namespace boost::asio::detail::socket_ops;
00150          packet.timestamp = network_to_host_long(packet.timestamp);
00151       }
00152 
00153       // send the data packet to the socket
00154       void send(socket_ptr psock, nsca_data_packet & packet) const
00155       {
00156          if(boost::asio::write(*psock, boost::asio::buffer(&packet, sizeof(packet))) != sizeof(packet))
00157          {
00158             throw std::runtime_error("failed to send packet to server");
00159          }
00160       }
00161 
00162       // send the status update to the server
00163       void send(nsca_data_packet const & send_packet) const
00164       {
00165          using namespace boost::asio::detail::socket_ops;
00166 
00167          // a copy of send_packet with the fields converted to network byte order
00168          nsca_data_packet hton_send_packet;
00169 
00170          // memcpy used as we need a binary copy (the padding is important) =/
00171          memcpy(&hton_send_packet, &send_packet, sizeof(hton_send_packet));
00172 
00173          // socket service
00174          boost::asio::io_service io_service;
00175          socket_ptr psock;
00176 
00177          // get the initialisation packet from the server
00178          nsca_init_packet init_packet;
00179 
00180          psock = connect(io_service);
00181          recv(psock, init_packet);
00182 
00183          // send the server the status update
00184          hton_send_packet.packet_version= host_to_network_short(nsca_const::NSCA_PACKET_VERSION);
00185          hton_send_packet.return_code = host_to_network_short(send_packet.return_code);
00186          hton_send_packet.timestamp = host_to_network_long(init_packet.timestamp);
00187          hton_send_packet.crc32_value = 0;
00188          hton_send_packet.crc32_value = host_to_network_long(crc32_.calculate(hton_send_packet));
00189 
00190          crypto_ptr pcrypto(
00191             new nsca_crypto(
00192                init_packet.iv,
00193                cfg_->enctype,
00194                cfg_->encpass
00195             ));
00196 
00197          pcrypto->encrypt(hton_send_packet);
00198 
00199 
00200          if(!psock) { psock = connect(io_service); }
00201          send(psock, hton_send_packet);
00202 
00203          if(pcrypto)
00204          {
00205             pcrypto->decrypt(hton_send_packet);
00206          }
00207 
00208       }
00209 
00210    private:
00211       boost::shared_ptr<nsca_config> cfg_;
00212       nsca_crc32 crc32_;
00213    };
00214 
00215 }}
00216 
00217 #endif