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