libmoost
|
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