artdaq_mfextensions  v1_03_01
UDP_receiver.cc
1 #include "mfextensions/Receivers/UDP_receiver.hh"
2 #include "mfextensions/Receivers/ReceiverMacros.hh"
3 #include "messagefacility/Utilities/ELseverityLevel.h"
4 #include <boost/tokenizer.hpp>
5 #include <boost/regex.hpp>
6 #include <sstream>
7 
8 mfviewer::UDPReceiver::UDPReceiver(fhicl::ParameterSet pset) : MVReceiver(pset)
9 , port_(pset.get<int>("port", 5140))
10 , io_service_()
11 , socket_(io_service_)
12 , debug_(pset.get<bool>("debug_mode", false))
13 {
14  //std::cout << "UDPReceiver Constructor" << std::endl;
15  boost::system::error_code ec;
16  udp::endpoint listen_endpoint(boost::asio::ip::address::from_string("0.0.0.0"), port_);
17  socket_.open(listen_endpoint.protocol());
18  boost::asio::socket_base::reuse_address option(true);
19  socket_.set_option(option, ec);
20  if (ec)
21  {
22  std::cerr << "An error occurred setting reuse_address: " << ec.message() << std::endl;
23  }
24  socket_.bind(listen_endpoint, ec);
25 
26  if (ec)
27  {
28  std::cerr << "An error occurred in bind(): " << ec.message() << std::endl;
29  }
30 
31  if (pset.get<bool>("multicast_enable", false))
32  {
33  std::string multicast_address_string = pset.get<std::string>("multicast_address", "227.128.12.27");
34  auto multicast_address = boost::asio::ip::address::from_string(multicast_address_string);
35  boost::asio::ip::multicast::join_group group_option(multicast_address);
36  socket_.set_option(group_option, ec);
37  if (ec)
38  {
39  std::cerr << "An error occurred joining the multicast group " << multicast_address_string
40  << ": " << ec.message() << std::endl;
41  }
42 
43  boost::asio::ip::multicast::enable_loopback loopback_option(true);
44  socket_.set_option(loopback_option, ec);
45 
46  if (ec)
47  {
48  std::cerr << "An error occurred setting the multicast loopback option: " << ec.message() << std::endl;
49  }
50  }
51  if (debug_) { std::cout << "UDPReceiver Constructor Done" << std::endl; }
52 }
53 
54 mfviewer::UDPReceiver::~UDPReceiver()
55 {
56  if (debug_) { std::cout << "Closing UDP Socket" << std::endl; }
57  socket_.close();
58 }
59 
60 void mfviewer::UDPReceiver::run()
61 {
62  while (!stopRequested_)
63  {
64  if (socket_.available() <= 0)
65  {
66  usleep(10000);
67  }
68  else
69  {
70  //usleep(500000);
71  udp::endpoint remote_endpoint;
72  boost::system::error_code ec;
73  size_t packetSize = socket_.receive_from(boost::asio::buffer(buffer_), remote_endpoint, 0, ec);
74  if (debug_) { std::cout << "Recieved message; validating...(packetSize=" << packetSize << ")" << std::endl; }
75  std::string message(buffer_, buffer_ + packetSize);
76  if (ec)
77  {
78  std::cerr << "Recieved error code: " << ec.message() << std::endl;
79  }
80  else if (packetSize > 0 && validate_packet(message))
81  {
82  if (debug_) { std::cout << "Valid UDP Message received! Sending to GUI!" << std::endl; }
83  emit NewMessage(read_msg(message));
84  //std::cout << std::endl << std::endl;
85  }
86  }
87  }
88  std::cout << "UDPReceiver shutting down!" << std::endl;
89 }
90 
91 qt_mf_msg mfviewer::UDPReceiver::read_msg(std::string input)
92 {
93  std::string hostname, category, application, message, hostaddr, file, line, module, eventID;
94  mf::ELseverityLevel sev;
95  timeval tv;
96  int pid = 0;
97  int seqNum = 0;
98 
99  if (debug_) { std::cout << "Recieved MF/Syslog message with contents: " << input << std::endl; }
100 
101  boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
102  typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
103  tokenizer tokens(input, sep);
104  tokenizer::iterator it = tokens.begin();
105 
106  //There may be syslog garbage in the first token before the timestamp...
107  boost::regex timestamp(".*?(\\d{2}-[^-]*-\\d{4}\\s\\d{2}:\\d{2}:\\d{2})");
108  boost::smatch res;
109  while (it != tokens.end() && !boost::regex_search(*it, res, timestamp))
110  {
111  ++it;
112  }
113 
114  if (it != tokens.end())
115  {
116  struct tm tm;
117  time_t t;
118  std::string value(res[1].first, res[1].second);
119  strptime(value.c_str(), "%d-%b-%Y %H:%M:%S", &tm);
120  tm.tm_isdst = -1;
121  t = mktime(&tm);
122  tv.tv_sec = t;
123  tv.tv_usec = 0;
124 
125  auto prevIt = it;
126  try
127  {
128  if (++it != tokens.end()) { seqNum = std::stoi(*it); }
129  }
130  catch (std::invalid_argument e) { it = prevIt; }
131  if (++it != tokens.end()) { hostname = *it; }
132  if (++it != tokens.end()) { hostaddr = *it; }
133  if (++it != tokens.end()) { sev = mf::ELseverityLevel(*it); }
134  if (++it != tokens.end()) { category = *it; }
135  if (++it != tokens.end()) { application = *it; }
136  prevIt = it;
137  try
138  {
139  if (++it != tokens.end()) { pid = std::stol(*it); }
140  }
141  catch (std::invalid_argument e) { it = prevIt; }
142  if (++it != tokens.end()) { eventID = *it; }
143  if (++it != tokens.end()) { module = *it; }
144 #if MESSAGEFACILITY_HEX_VERSION >= 0x20201 // Sender and receiver version must match!
145  if (++it != tokens.end()) { file = *it; }
146  if (++it != tokens.end()) { line = *it; }
147 #endif
148  std::ostringstream oss;
149  bool first = true;
150  while (++it != tokens.end())
151  {
152  if (!first) { oss << "|"; }
153  else { first = false; }
154  oss << *it;
155  }
156  if (debug_) { std::cout << "Message content: " << oss.str() << std::endl; }
157  message = oss.str();
158  }
159 
160  qt_mf_msg msg(hostname, category, application, pid, tv);
161  msg.setSeverity(sev);
162  msg.setMessage("UDPMessage", seqNum, message);
163  msg.setHostAddr(hostaddr);
164  msg.setFileName(file);
165  msg.setLineNumber(line);
166  msg.setModule(module);
167  msg.setEventID(eventID);
168  msg.updateText();
169 
170  return msg;
171 }
172 
173 bool mfviewer::UDPReceiver::validate_packet(std::string input)
174 {
175  // Run some checks on the input packet
176  if (input.find("MF") == std::string::npos)
177  {
178  std::cout << "Failed to find \"MF\" in message: " << input << std::endl;
179  return false;
180  }
181  if (input.find("|") == std::string::npos)
182  {
183  std::cout << "Failed to find | separator character in message: " << input << std::endl;
184  return false;
185  }
186  return true;
187 }
188 
189 #include "moc_UDP_receiver.cpp"
190 
191 DEFINE_MFVIEWER_RECEIVER(mfviewer::UDPReceiver)
Receive messages through a UDP socket. Expects the syslog format provided by UDP_mfPlugin (ELUDP) ...
Definition: UDP_receiver.hh:16
Qt wrapper around MessageFacility message
Definition: qt_mf_msg.hh:37