1 #include "cetlib/PluginTypeDeducer.h"
2 #include "fhiclcpp/ParameterSet.h"
4 #include "messagefacility/MessageService/ELdestination.h"
5 #include "messagefacility/Utilities/ELseverityLevel.h"
6 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // v2_02_01 is s67
7 # include "messagefacility/MessageService/MessageDrop.h"
9 # include "messagefacility/MessageLogger/MessageLogger.h"
11 #include "messagefacility/Utilities/exception.h"
12 #include "cetlib/compiler_macros.h"
19 #include <arpa/inet.h>
22 #include <netinet/in.h>
25 #define TRACE_NAME "UDP_mfPlugin"
29 #include <boost/algorithm/string.hpp>
31 #if MESSAGEFACILITY_HEX_VERSION < 0x20201 // format changed to format_ for s67
32 #define format_ format
37 using mf::service::ELdestination;
38 using mf::ELseverityLevel;
45 class ELUDP :
public ELdestination
47 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
50 fhicl::TableFragment<ELdestination::Config> elDestConfig;
51 fhicl::Atom<int> error_max{ fhicl::Name{
"error_turnoff_threshold" },fhicl::Comment{
"Number of errors before turning off destination (default: 0, don't turn off)" },0 };
52 fhicl::Atom<int> error_report{ fhicl::Name{
"error_report_backoff_factor" },fhicl::Comment{
"Print an error message every N errors" },100 };
53 fhicl::Atom<std::string> host{ fhicl::Name{
"host" },fhicl::Comment{
"Address to send messages to" },
"227.128.12.27" };
54 fhicl::Atom<int> port{ fhicl::Name{
"port" },fhicl::Comment{
"Port to send messages to" },5140 };
55 fhicl::Atom<bool> multicast_enabled{ fhicl::Name{
"multicast_enabled"},fhicl::Comment{
"Whether messages should be sent via multicast"},
false };
57 fhicl::Atom<std::string> output_address{ fhicl::Name{
"multicast_interface_ip" }, fhicl::Comment{
"Use this hostname for multicast output(to assign to the proper NIC)" },
"0.0.0.0" };
59 using Parameters = fhicl::WrappedTable<Config>;
66 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
67 ELUDP(
const fhicl::ParameterSet& pset);
69 ELUDP(Parameters
const& pset);
77 virtual void fillPrefix(std::ostringstream& o,
const ErrorObj& e)
override;
84 virtual void fillUsrMsg(std::ostringstream& o,
const ErrorObj& e)
override;
89 virtual void fillSuffix(std::ostringstream&,
const ErrorObj&)
override {}
96 virtual void routePayload(
const std::ostringstream& o,
const ErrorObj& e)
override;
102 int error_report_backoff_factor_;
106 bool multicast_enabled_;
107 std::string multicast_out_addr_;
110 struct sockaddr_in message_addr_;
113 int consecutive_success_count_;
115 int next_error_report_;
120 std::string hostname_;
121 std::string hostaddr_;
134 #if MESSAGEFACILITY_HEX_VERSION < 0x20103 // v2_01_03 is s58, pre v2_01_03 is s50
136 : ELdestination(pset)
137 , error_report_backoff_factor_(pset.get<int>(
"error_report_backoff_factor", 100))
138 , error_max_(pset.get<int>(
"error_turnoff_threshold", 0))
139 , host_(pset.get<std::string>(
"host",
"227.128.12.27"))
140 , port_(pset.get<int>(
"port", 5140))
141 , multicast_enabled_(pset.get<bool>(
"multicast_enabled", false))
142 , multicast_out_addr_(pset.get<std::string>(
"multicast_interface_ip", pset.get<std::string>(
"output_address",
"0.0.0.0")))
145 : ELdestination(pset().elDestConfig())
146 , error_report_backoff_factor_(pset().error_report())
147 , error_max_(pset().error_max())
148 , host_(pset().host())
149 , port_(pset().port())
150 , multicast_enabled_(pset().multicast_enabled())
151 , multicast_out_addr_(pset().output_address())
153 , message_socket_(-1)
154 , consecutive_success_count_(0)
156 , next_error_report_(1)
158 , pid_(static_cast<long>(getpid()))
161 char hostname_c[1024];
162 hostname_ = (gethostname(hostname_c, 1023) == 0) ? hostname_c :
"Unkonwn Host";
165 hostent* host =
nullptr;
166 host = gethostbyname(hostname_c);
171 char* ip = inet_ntoa(*(
struct in_addr *)host->h_addr);
177 struct ifaddrs* ifAddrStruct =
nullptr;
178 struct ifaddrs* ifa =
nullptr;
179 void* tmpAddrPtr =
nullptr;
181 if (getifaddrs(&ifAddrStruct))
184 hostaddr_ =
"127.0.0.1";
189 for (ifa = ifAddrStruct; ifa !=
nullptr; ifa = ifa->ifa_next)
191 if (ifa->ifa_addr->sa_family == AF_INET)
194 tmpAddrPtr = &((
struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
195 char addressBuffer[INET_ADDRSTRLEN];
196 inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
197 hostaddr_ = addressBuffer;
200 else if (ifa->ifa_addr->sa_family == AF_INET6)
203 tmpAddrPtr = &((
struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
204 char addressBuffer[INET6_ADDRSTRLEN];
205 inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
206 hostaddr_ = addressBuffer;
210 if (!hostaddr_.empty()
211 && hostaddr_.compare(
"127.0.0.1")
212 && hostaddr_.compare(
"::1"))
216 if (hostaddr_.empty())
217 hostaddr_ =
"127.0.0.1";
224 std::ostringstream pid_ostr;
225 pid_ostr <<
"/proc/" << pid_ <<
"/exe";
226 exe = realpath(pid_ostr.str().c_str(), NULL);
228 size_t end = exe.find(
'\0');
229 size_t start = exe.find_last_of(
'/', end);
231 app_ = exe.substr(start + 1, end - start - 1);
234 std::stringstream ss;
235 ss <<
"//proc//" << pid_ <<
"//cmdline";
236 std::ifstream procfile{ ss.str().c_str() };
238 std::string procinfo;
240 if (procfile.is_open())
242 procfile >> procinfo;
246 size_t end = procinfo.find(
'\0');
247 size_t start = procinfo.find_last_of(
'/', end);
249 app_ = procinfo.substr(start + 1, end - start - 1);
253 void ELUDP::reconnect_()
255 message_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
256 if (message_socket_ < 0)
258 TLOG(TLVL_ERROR) <<
"I failed to create the socket for sending Data messages! err=" << strerror(errno);
261 int sts =
ResolveHost(host_.c_str(), port_, message_addr_);
264 TLOG(TLVL_ERROR) <<
"Unable to resolve Data message address, err=" << strerror(errno);
268 if (multicast_out_addr_ ==
"0.0.0.0")
270 multicast_out_addr_.reserve(HOST_NAME_MAX);
271 sts = gethostname(&multicast_out_addr_[0], HOST_NAME_MAX);
274 TLOG(TLVL_ERROR) <<
"Could not get current hostname, err=" << strerror(errno);
279 if (multicast_out_addr_ !=
"localhost")
286 TLOG(TLVL_ERROR) <<
"Unable to resolve multicast interface address, err=" << strerror(errno);
290 if (setsockopt(message_socket_, IPPROTO_IP, IP_MULTICAST_IF, &addr,
sizeof(addr)) == -1)
292 TLOG(TLVL_ERROR) <<
"Cannot set outgoing interface, err=" << strerror(errno);
297 if (setsockopt(message_socket_, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0)
299 TLOG(TLVL_ERROR) <<
"Unable to enable port reuse on message socket, err=" << strerror(errno);
302 if (setsockopt(message_socket_, IPPROTO_IP, IP_MULTICAST_LOOP, &yes,
sizeof(yes)) < 0)
304 TLOG(TLVL_ERROR) <<
"Unable to enable multicast loopback on message socket, err=" << strerror(errno);
307 if (setsockopt(message_socket_, SOL_SOCKET, SO_BROADCAST, (
void*)&yes,
sizeof(
int)) == -1)
309 TLOG(TLVL_ERROR) <<
"Cannot set message socket to broadcast, err=" << strerror(errno);
319 const auto& xid = msg.xid();
322 auto module = xid.module();
324 std::replace(
id.begin(),
id.end(),
'|',
'!');
325 std::replace(app.begin(), app.end(),
'|',
'!');
326 std::replace(module.begin(), module.end(),
'|',
'!');
328 oss << format_.timestamp(msg.timestamp()) <<
"|";
329 oss << std::to_string(++seqNum_) <<
"|";
330 oss << hostname_ <<
"|";
331 oss << hostaddr_ <<
"|";
332 oss << xid.severity().getName() <<
"|";
335 # if MESSAGEFACILITY_HEX_VERSION >= 0x20201 // an indication of s67
337 oss << mf::GetIteration() <<
"|";
340 oss << mf::MessageDrop::instance()->iteration <<
"|";
342 oss << module <<
"|";
343 #if MESSAGEFACILITY_HEX_VERSION >= 0x20201
344 oss << msg.filename() <<
"|" << std::to_string(msg.lineNumber()) <<
"|";
353 std::ostringstream tmposs;
355 for (
auto const& val : msg.items())
361 const std::string& usrMsg = !tmposs.str().compare(0, 1,
"\n") ? tmposs.str().erase(0, 1) : tmposs.str();
371 if (message_socket_ == -1) reconnect_();
372 if (error_count_ < error_max_ || error_max_ == 0)
374 char str[INET_ADDRSTRLEN];
375 inet_ntop(AF_INET, &(message_addr_.sin_addr), str, INET_ADDRSTRLEN);
377 auto string =
"UDPMFMESSAGE" + std::to_string(pid_) +
"|" + oss.str();
378 auto sts = sendto(message_socket_,
string.c_str(),
string.size(), 0, (
struct sockaddr *)&message_addr_,
sizeof(message_addr_));
382 consecutive_success_count_ = 0;
384 if (error_count_ == next_error_report_)
386 TLOG(TLVL_ERROR) <<
"Error sending message " << seqNum_ <<
" to " << host_ <<
", errno=" << errno <<
" (" << strerror(errno) <<
")";
387 next_error_report_ *= error_report_backoff_factor_;
392 ++consecutive_success_count_;
393 if (consecutive_success_count_ >= 5)
396 next_error_report_ = 1;
409 #ifndef EXTERN_C_FUNC_DECLARE_START
410 #define EXTERN_C_FUNC_DECLARE_START extern "C" {
413 EXTERN_C_FUNC_DECLARE_START
414 auto makePlugin(
const std::string&,
415 const fhicl::ParameterSet& pset)
417 return std::make_unique<mfplugins::ELUDP>(pset);
421 DEFINE_BASIC_PLUGINTYPE_FUNC(mf::service::ELdestination)
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Message Facility UDP Streamer Destination Formats messages into a delimited string and sends via UDP ...
int GetInterfaceForNetwork(char const *host_in, in_addr &addr)
Convert an IP address to the network address of the interface sharing the subnet mask.
ELUDP(const fhicl::ParameterSet &pset)
ELUDP Constructor
virtual void routePayload(const std::ostringstream &o, const ErrorObj &e) override
Serialize a MessageFacility message to the output.
virtual void fillUsrMsg(std::ostringstream &o, const ErrorObj &e) override
Fill the "User Message" portion of the message.
virtual void fillPrefix(std::ostringstream &o, const ErrorObj &e) override
Fill the "Prefix" portion of the message.
virtual void fillSuffix(std::ostringstream &, const ErrorObj &) override
Fill the "Suffix" portion of the message (Unused)