artdaq_mfextensions  v1_03_07
UDP_receiver.cc
1 #define TRACE_NAME "UDP_Receiver"
2 
3 #include "mfextensions/Receivers/UDP_receiver.hh"
4 #include <sys/poll.h>
5 #include <boost/tokenizer.hpp>
6 #include <sstream>
7 #include "messagefacility/Utilities/ELseverityLevel.h"
8 #include "mfextensions/Receivers/ReceiverMacros.hh"
10 
11 mfviewer::UDPReceiver::UDPReceiver(fhicl::ParameterSet pset)
12  : MVReceiver(pset), message_port_(pset.get<int>("port", 5140)), message_addr_(pset.get<std::string>("message_address", "227.128.12.27")), multicast_enable_(pset.get<bool>("multicast_enable", false)), multicast_out_addr_(pset.get<std::string>("multicast_interface_ip", "0.0.0.0")), message_socket_(-1), timestamp_regex_("(\\d{2}-[^-]*-\\d{4}\\s\\d{2}:\\d{2}:\\d{2})"), file_line_regex_("^\\s*([^:]*\\.[^:]{1,3}):(\\d+)(.*)")
13 {
14  TLOG(TLVL_TRACE) << "UDPReceiver Constructor";
15 }
16 
17 void mfviewer::UDPReceiver::setupMessageListener_()
18 {
19  TLOG(TLVL_INFO) << "Setting up message listen socket, address=" << message_addr_ << ":" << message_port_;
20  message_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
21  if (message_socket_ < 0)
22  {
23  TLOG(TLVL_ERROR) << "Error creating socket for receiving messages! err=" << strerror(errno);
24  exit(1);
25  }
26 
27  struct sockaddr_in si_me_request;
28 
29  int yes = 1;
30  if (setsockopt(message_socket_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
31  {
32  TLOG(TLVL_ERROR) << "Unable to enable port reuse on message socket, err=" << strerror(errno);
33  exit(1);
34  }
35  memset(&si_me_request, 0, sizeof(si_me_request));
36  si_me_request.sin_family = AF_INET;
37  si_me_request.sin_port = htons(message_port_);
38  si_me_request.sin_addr.s_addr = htonl(INADDR_ANY);
39  if (bind(message_socket_, (struct sockaddr*)&si_me_request, sizeof(si_me_request)) == -1)
40  {
41  TLOG(TLVL_ERROR) << "Cannot bind message socket to port " << message_port_ << ", err=" << strerror(errno);
42  exit(1);
43  }
44 
45  if (message_addr_ != "localhost" && multicast_enable_)
46  {
47  struct ip_mreq mreq;
48  int sts = ResolveHost(message_addr_.c_str(), mreq.imr_multiaddr);
49  if (sts == -1)
50  {
51  TLOG(TLVL_ERROR) << "Unable to resolve multicast message address, err=" << strerror(errno);
52  exit(1);
53  }
54  sts = GetInterfaceForNetwork(multicast_out_addr_.c_str(), mreq.imr_interface);
55  if (sts == -1)
56  {
57  TLOG(TLVL_ERROR) << "Unable to resolve hostname for " << multicast_out_addr_;
58  exit(1);
59  }
60  if (setsockopt(message_socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
61  {
62  TLOG(TLVL_ERROR) << "Unable to join multicast group, err=" << strerror(errno);
63  exit(1);
64  }
65  }
66  TLOG(TLVL_INFO) << "Done setting up message receive socket";
67 }
68 
70 {
71  TLOG(TLVL_DEBUG) << "Closing message receive socket";
72  close(message_socket_);
73  message_socket_ = -1;
74 }
75 
77 {
78  while (!stopRequested_)
79  {
80  if (message_socket_ == -1) setupMessageListener_();
81 
82  int ms_to_wait = 10;
83  struct pollfd ufds[1];
84  ufds[0].fd = message_socket_;
85  ufds[0].events = POLLIN | POLLPRI | POLLERR;
86  int rv = poll(ufds, 1, ms_to_wait);
87 
88  // Continue loop if no message received or message does not have correct event ID
89  if (rv <= 0 || (ufds[0].revents != POLLIN && ufds[0].revents != POLLPRI))
90  {
91  if (rv == 1 && (ufds[0].revents & (POLLNVAL | POLLERR | POLLHUP)))
92  {
93  close(message_socket_);
94  message_socket_ = -1;
95  }
96  if (stopRequested_)
97  {
98  break;
99  }
100  continue;
101  }
102 
103  char buffer[TRACE_STREAMER_MSGMAX + 1];
104  auto packetSize = read(message_socket_, &buffer, TRACE_STREAMER_MSGMAX);
105  if (packetSize < 0)
106  {
107  TLOG(TLVL_ERROR) << "Error receiving message, errno=" << errno << " (" << strerror(errno) << ")";
108  }
109  else
110  {
111  TLOG(TLVL_TRACE) << "Recieved message; validating...(packetSize=" << packetSize << ")";
112  std::string message(buffer, buffer + packetSize);
113  if (validate_packet(message))
114  {
115  TLOG(TLVL_TRACE) << "Valid UDP Message received! Sending to GUI!";
116  emit NewMessage(read_msg(message));
117  }
118  }
119  }
120  TLOG(TLVL_INFO) << "UDPReceiver shutting down!";
121 }
122 
124 {
125  std::string hostname, category, application, message, hostaddr, file, line, module, eventID;
126  mf::ELseverityLevel sev;
127  timeval tv = {0, 0};
128  int pid = 0;
129  int seqNum = 0;
130 
131  TLOG(TLVL_TRACE) << "Recieved MF/Syslog message with contents: " << input;
132 
133  boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
134  typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
135  tokenizer tokens(input, sep);
136  tokenizer::iterator it = tokens.begin();
137 
138  // There may be syslog garbage in the first token before the timestamp...
139  boost::smatch res;
140  while (it != tokens.end() && !boost::regex_search(*it, res, timestamp_regex_))
141  {
142  ++it;
143  }
144 
145  if (it != tokens.end())
146  {
147  struct tm tm;
148  time_t t;
149  std::string value(res[1].first, res[1].second);
150  strptime(value.c_str(), "%d-%b-%Y %H:%M:%S", &tm);
151  tm.tm_isdst = -1;
152  t = mktime(&tm);
153  tv.tv_sec = t;
154  tv.tv_usec = 0;
155 
156  auto prevIt = it;
157  try
158  {
159  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
160  {
161  seqNum = std::stoi(*it);
162  }
163  }
164  catch (const std::invalid_argument& e)
165  {
166  it = prevIt;
167  }
168  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
169  {
170  hostname = *it;
171  }
172  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
173  {
174  hostaddr = *it;
175  }
176  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
177  {
178  sev = mf::ELseverityLevel(*it);
179  }
180  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
181  {
182  category = *it;
183  }
184  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
185  {
186  application = *it;
187  }
188  prevIt = it;
189  try
190  {
191  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
192  {
193  pid = std::stol(*it);
194  }
195  }
196  catch (const std::invalid_argument& e)
197  {
198  it = prevIt;
199  }
200  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
201  {
202  eventID = *it;
203  }
204  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
205  {
206  module = *it;
207  }
208  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
209  {
210  file = *it;
211  }
212  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
213  {
214  line = *it;
215  }
216  std::ostringstream oss;
217  bool first = true;
218  while (it != tokens.end() && ++it != tokens.end() /* Advances it */)
219  {
220  if (!first)
221  {
222  oss << "|";
223  }
224  else
225  {
226  first = false;
227  }
228  oss << *it;
229  }
230  TLOG(TLVL_TRACE) << "Message content: " << oss.str();
231  message = oss.str();
232  }
233 
234  qt_mf_msg msg(hostname, category, application, pid, tv);
235  msg.setSeverity(sev);
236  msg.setMessage("UDPMessage", seqNum, message);
237  msg.setHostAddr(hostaddr);
238  msg.setFileName(file);
239  msg.setLineNumber(line);
240  msg.setModule(module);
241  msg.setEventID(eventID);
242  msg.updateText();
243 
244  return msg;
245 }
246 
248 {
249  // Run some checks on the input packet
250  if (input.find("MF") == std::string::npos)
251  {
252  TLOG(TLVL_WARNING) << "Failed to find \"MF\" in message: " << input;
253  return false;
254  }
255  if (input.find("|") == std::string::npos)
256  {
257  TLOG(TLVL_WARNING) << "Failed to find | separator character in message: " << input;
258  return false;
259  }
260  return true;
261 }
262 
263 #include "moc_UDP_receiver.cpp"
264 
265 DEFINE_MFVIEWER_RECEIVER(mfviewer::UDPReceiver)
void updateText()
Parse fields and create HTML string representing message
Definition: qt_mf_msg.cc:51
void setEventID(std::string eventID)
Set the Event ID of the message
Definition: qt_mf_msg.hh:140
void run() override
Receiver method. Receive messages and emit NewMessage signal
Definition: UDP_receiver.cc:76
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Definition: TCPConnect.hh:42
static bool validate_packet(std::string input)
Run simple validation tests on message
void setFileName(std::string file)
Set the file name field
Definition: qt_mf_msg.hh:125
Receive messages through a UDP socket. Expects the syslog format provided by UDP_mfPlugin (ELUDP) ...
Definition: UDP_receiver.hh:13
UDPReceiver(fhicl::ParameterSet pset)
UDPReceiver Constructor
Definition: UDP_receiver.cc:11
Qt wrapper around MessageFacility message
Definition: qt_mf_msg.hh:36
int GetInterfaceForNetwork(char const *host_in, in_addr &addr)
Convert an IP address to the network address of the interface sharing the subnet mask.
Definition: TCPConnect.hh:90
void setMessage(std::string prefix, int iteration, std::string msg)
Set the message
Definition: qt_mf_msg.cc:44
virtual ~UDPReceiver()
Destructor – Close socket
Definition: UDP_receiver.cc:69
A MVReceiver class listens for messages and raises a signal when one arrives
Definition: MVReceiver.hh:17
void setSeverity(mf::ELseverityLevel sev)
Set the Severity of the message (MF levels)
Definition: qt_mf_msg.cc:13
void setHostAddr(std::string hostaddr)
Set the hostaddr field
Definition: qt_mf_msg.hh:120
void setLineNumber(std::string line)
Set the line number field
Definition: qt_mf_msg.hh:130
qt_mf_msg read_msg(std::string input)
Parse incoming message
void setModule(std::string module)
Set the module name
Definition: qt_mf_msg.hh:135