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