00001 #include "cetlib/PluginTypeDeducer.h"
00002 #include "fhiclcpp/ParameterSet.h"
00003
00004 #include "messagefacility/MessageService/ELdestination.h"
00005 #include "messagefacility/Utilities/ELseverityLevel.h"
00006 #if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
00007 # include "messagefacility/MessageService/ELcontextSupplier.h"
00008 # include "messagefacility/MessageLogger/MessageDrop.h"
00009 #else
00010 # include "messagefacility/MessageService/MessageDrop.h"
00011 #endif
00012 #include "messagefacility/Utilities/exception.h"
00013
00014
00015 #include <iostream>
00016 #include <fstream>
00017 #include <memory>
00018 #include <algorithm>
00019 #include <arpa/inet.h>
00020 #include <ifaddrs.h>
00021 #include <netdb.h>
00022 #include <netinet/in.h>
00023
00024
00025
00026 #include <boost/asio.hpp>
00027 #include <boost/algorithm/string.hpp>
00028
00029 namespace mfplugins
00030 {
00031 using mf::service::ELdestination;
00032 using mf::ELseverityLevel;
00033 using mf::ErrorObj;
00034 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
00035 using mf::service::ELcontextSupplier;
00036 # endif
00037 using boost::asio::ip::udp;
00038
00043 class ELUDP : public ELdestination
00044 {
00045 public:
00046
00047 ELUDP(const fhicl::ParameterSet& pset);
00048
00049 virtual void fillPrefix(std::ostringstream&, const ErrorObj&
00050 # if MESSAGEFACILITY_HEX_VERSION < 0x20002
00051 , const ELcontextSupplier&
00052 # endif
00053 ) override;
00054
00055 virtual void fillUsrMsg(std::ostringstream&, const ErrorObj&) override;
00056
00057 virtual void fillSuffix(std::ostringstream&, const ErrorObj&) override {}
00058
00059 virtual void routePayload(const std::ostringstream&, const ErrorObj&
00060 # if MESSAGEFACILITY_HEX_VERSION < 0x20002
00061 , const ELcontextSupplier&
00062 # endif
00063 ) override;
00064
00065 private:
00066 void reconnect_(bool quiet = false);
00067
00068 boost::asio::io_service io_service_;
00069 udp::socket socket_;
00070 udp::endpoint remote_endpoint_;
00071 int consecutive_success_count_;
00072 int error_count_;
00073 int next_error_report_;
00074 int error_report_backoff_factor_;
00075 int error_max_;
00076 std::string host_;
00077 int port_;
00078 int seqNum_;
00079
00080
00081 long pid_;
00082 std::string hostname_;
00083 std::string hostaddr_;
00084 std::string app_;
00085 };
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 ELUDP::ELUDP(const fhicl::ParameterSet& pset)
00097 : ELdestination(pset)
00098 , io_service_()
00099 , socket_(io_service_)
00100 , remote_endpoint_()
00101 , consecutive_success_count_(0)
00102 , error_count_(0)
00103 , next_error_report_(1)
00104 , error_report_backoff_factor_(pset.get<int>("error_report_backoff_factor", 10))
00105 , error_max_(pset.get<int>("error_turnoff_threshold", 1))
00106 , host_(pset.get<std::string>("host", "227.128.12.27"))
00107 , port_(pset.get<int>("port", 5140))
00108 , seqNum_(0)
00109 , pid_(static_cast<long>(getpid()))
00110 {
00111 reconnect_();
00112
00113
00114 char hostname_c[1024];
00115 hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c : "Unkonwn Host";
00116
00117
00118 hostent* host = nullptr;
00119 host = gethostbyname(hostname_c);
00120
00121 if (host != nullptr)
00122 {
00123
00124 char* ip = inet_ntoa(*(struct in_addr *)host->h_addr);
00125 hostaddr_ = ip;
00126 }
00127 else
00128 {
00129
00130 struct ifaddrs* ifAddrStruct = nullptr;
00131 struct ifaddrs* ifa = nullptr;
00132 void* tmpAddrPtr = nullptr;
00133
00134 if (getifaddrs(&ifAddrStruct))
00135 {
00136
00137 hostaddr_ = "127.0.0.1";
00138 }
00139 else
00140 {
00141
00142 for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
00143 {
00144 if (ifa->ifa_addr->sa_family == AF_INET)
00145 {
00146
00147 tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
00148 char addressBuffer[INET_ADDRSTRLEN];
00149 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
00150 hostaddr_ = addressBuffer;
00151 }
00152
00153 else if (ifa->ifa_addr->sa_family == AF_INET6)
00154 {
00155
00156 tmpAddrPtr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
00157 char addressBuffer[INET6_ADDRSTRLEN];
00158 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
00159 hostaddr_ = addressBuffer;
00160 }
00161
00162
00163 if (!hostaddr_.empty()
00164 && hostaddr_.compare("127.0.0.1")
00165 && hostaddr_.compare("::1"))
00166 break;
00167 }
00168
00169 if (hostaddr_.empty())
00170 hostaddr_ = "127.0.0.1";
00171 }
00172 }
00173
00174 #if 0
00175
00176 std::string exe;
00177 std::ostringstream pid_ostr;
00178 pid_ostr << "/proc/" << pid_ << "/exe";
00179 exe = realpath(pid_ostr.str().c_str(), NULL);
00180
00181 size_t end = exe.find('\0');
00182 size_t start = exe.find_last_of('/', end);
00183
00184 app_ = exe.substr(start + 1, end - start - 1);
00185 #else
00186
00187 std::stringstream ss;
00188 ss << "//proc//" << pid_ << "//cmdline";
00189 std::ifstream procfile{ ss.str().c_str() };
00190
00191 std::string procinfo;
00192
00193 if (procfile.is_open())
00194 {
00195 procfile >> procinfo;
00196 procfile.close();
00197 }
00198
00199 size_t end = procinfo.find('\0');
00200 size_t start = procinfo.find_last_of('/', end);
00201
00202 app_ = procinfo.substr(start + 1, end - start - 1);
00203 #endif
00204 }
00205
00206 void ELUDP::reconnect_(bool quiet)
00207 {
00208 boost::system::error_code ec;
00209 socket_.open(udp::v4());
00210 socket_.set_option(boost::asio::socket_base::reuse_address(true), ec);
00211 if (ec && !quiet)
00212 {
00213 std::cerr << "An error occurred setting reuse_address to true: "
00214 << ec.message() << std::endl;
00215 }
00216
00217 if (boost::iequals(host_, "Broadcast") || host_ == "255.255.255.255")
00218 {
00219 socket_.set_option(boost::asio::socket_base::broadcast(true), ec);
00220 remote_endpoint_ = udp::endpoint(boost::asio::ip::address_v4::broadcast(), port_);
00221 }
00222 else
00223 {
00224 udp::resolver resolver(io_service_);
00225 udp::resolver::query query(udp::v4(), host_, std::to_string(port_));
00226 remote_endpoint_ = *resolver.resolve(query);
00227 }
00228
00229 socket_.connect(remote_endpoint_, ec);
00230 if (ec)
00231 {
00232 if (!quiet)
00233 {
00234 std::cerr << "An Error occurred in connect(): " << ec.message() << std::endl
00235 << " endpoint = " << remote_endpoint_ << std::endl;
00236 }
00237 error_count_++;
00238 }
00239
00240
00241
00242
00243 }
00244
00245
00246
00247
00248 void ELUDP::fillPrefix(std::ostringstream& oss, const ErrorObj& msg
00249 # if MESSAGEFACILITY_HEX_VERSION < 0x20002
00250 , ELcontextSupplier const&
00251 # endif
00252 )
00253 {
00254 const auto& xid = msg.xid();
00255
00256 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
00257 auto id = xid.id();
00258 auto module = xid.module();
00259 auto app = app_;
00260 # else
00261 auto id = xid.id;
00262 auto app = xid.application;
00263 auto process = xid.process;
00264 auto module = xid.module;
00265 # endif
00266 std::replace(id.begin(), id.end(), '|', '!');
00267 std::replace(app.begin(), app.end(), '|', '!');
00268 # if MESSAGEFACILITY_HEX_VERSION < 0x20002 // v2_00_02 is s50, pre v2_00_02 is s48
00269 std::replace(process.begin(), process.end(), '|', '!');
00270 # endif
00271 std::replace(module.begin(), module.end(), '|', '!');
00272
00273 oss << format.timestamp(msg.timestamp()) << "|";
00274 oss << std::to_string(++seqNum_) << "|";
00275 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
00276 oss << hostname_ << "|";
00277 oss << hostaddr_ << "|";
00278 oss << xid.severity().getName() << "|";
00279 # else
00280 oss << xid.hostname << "|";
00281 oss << xid.hostaddr << "|";
00282 oss << xid.severity.getName() << "|";
00283 # endif
00284 oss << id << "|";
00285 oss << app << "|";
00286 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
00287 oss << pid_ << "|";
00288 oss << mf::MessageDrop::instance()->iteration << "|";
00289 # else
00290 oss << process << "|";
00291 oss << xid.pid << "|";
00292 oss << mf::MessageDrop::instance()->runEvent << "|";
00293 # endif
00294 oss << module << "|";
00295 }
00296
00297
00298
00299
00300 void ELUDP::fillUsrMsg(std::ostringstream& oss, const ErrorObj& msg)
00301 {
00302 std::ostringstream tmposs;
00303 ELdestination::fillUsrMsg(tmposs, msg);
00304
00305
00306 const std::string& usrMsg = !tmposs.str().compare(0, 1, "\n") ? tmposs.str().erase(0, 1) : tmposs.str();
00307
00308 oss << usrMsg;
00309 }
00310
00311
00312
00313
00314 void ELUDP::routePayload(const std::ostringstream& oss
00315 #if MESSAGEFACILITY_HEX_VERSION < 0x20002
00316 , const ErrorObj& msg, ELcontextSupplier const&
00317 #else
00318 , const ErrorObj&
00319 #endif
00320 )
00321 {
00322 if (error_count_ < error_max_)
00323 {
00324 # if MESSAGEFACILITY_HEX_VERSION >= 0x20002 // an indication of a switch from s48 to s50
00325 auto pid = pid_;
00326 # else
00327 auto pid = msg.xid().pid;
00328 # endif
00329
00330 auto string = "UDPMFMESSAGE" + std::to_string(pid) + "|" + oss.str();
00331
00332 auto message = boost::asio::buffer(string);
00333 bool error = true;
00334 try
00335 {
00336 socket_.send_to(message, remote_endpoint_);
00337 ++consecutive_success_count_;
00338 if (consecutive_success_count_ >= 5)
00339 {
00340 error_count_ = 0;
00341 next_error_report_ = 1;
00342 }
00343 error = false;
00344 }
00345 catch (boost::system::system_error& err)
00346 {
00347 consecutive_success_count_ = 0;
00348 ++error_count_;
00349 if (error_count_ == next_error_report_)
00350 {
00351 std::cerr << "An exception occurred when trying to send message " << std::to_string(seqNum_) << " to "
00352 << remote_endpoint_ << std::endl
00353 << " message = " << oss.str() << std::endl
00354 << " exception = " << err.what() << std::endl;
00355 next_error_report_ *= error_report_backoff_factor_;
00356 }
00357 }
00358 if (error)
00359 {
00360 try
00361 {
00362 reconnect_(true);
00363 }
00364 catch (...) {}
00365 }
00366 }
00367 }
00368 }
00369
00370
00371
00372
00373
00374
00375
00376 extern "C"
00377 {
00378 auto makePlugin(const std::string&,
00379 const fhicl::ParameterSet& pset)
00380 {
00381 return std::make_unique<mfplugins::ELUDP>(pset);
00382 }
00383 }
00384
00385 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)