artdaq_mfextensions  v1_04_00
UDP_receiver.cc
1 #define TRACE_NAME "UDP_Receiver"
2 
3 #include "mfextensions/Receivers/UDP_receiver.hh"
4 #include <sys/poll.h>
5 #include <sstream>
6 #include "messagefacility/Utilities/ELseverityLevel.h"
7 #include "mfextensions/Receivers/ReceiverMacros.hh"
9 
10 mfviewer::UDPReceiver::UDPReceiver(fhicl::ParameterSet pset)
11  : 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)
12 {
13  TLOG(TLVL_TRACE) << "UDPReceiver Constructor";
14 }
15 
16 void mfviewer::UDPReceiver::setupMessageListener_()
17 {
18  TLOG(TLVL_INFO) << "Setting up message listen socket, address=" << message_addr_ << ":" << message_port_;
19  message_socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
20  if (message_socket_ < 0)
21  {
22  TLOG(TLVL_ERROR) << "Error creating socket for receiving messages! err=" << strerror(errno);
23  exit(1);
24  }
25 
26  struct sockaddr_in si_me_request;
27 
28  int yes = 1;
29  if (setsockopt(message_socket_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
30  {
31  TLOG(TLVL_ERROR) << "Unable to enable port reuse on message socket, err=" << strerror(errno);
32  exit(1);
33  }
34  memset(&si_me_request, 0, sizeof(si_me_request));
35  si_me_request.sin_family = AF_INET;
36  si_me_request.sin_port = htons(message_port_);
37  si_me_request.sin_addr.s_addr = htonl(INADDR_ANY);
38  if (bind(message_socket_, (struct sockaddr*)&si_me_request, sizeof(si_me_request)) == -1)
39  {
40  TLOG(TLVL_ERROR) << "Cannot bind message socket to port " << message_port_ << ", err=" << strerror(errno);
41  exit(1);
42  }
43 
44  if (message_addr_ != "localhost" && multicast_enable_)
45  {
46  struct ip_mreq mreq;
47  int sts = ResolveHost(message_addr_.c_str(), mreq.imr_multiaddr);
48  if (sts == -1)
49  {
50  TLOG(TLVL_ERROR) << "Unable to resolve multicast message address, err=" << strerror(errno);
51  exit(1);
52  }
53  sts = GetInterfaceForNetwork(multicast_out_addr_.c_str(), mreq.imr_interface);
54  if (sts == -1)
55  {
56  TLOG(TLVL_ERROR) << "Unable to resolve hostname for " << multicast_out_addr_;
57  exit(1);
58  }
59  if (setsockopt(message_socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
60  {
61  TLOG(TLVL_ERROR) << "Unable to join multicast group, err=" << strerror(errno);
62  exit(1);
63  }
64  }
65  TLOG(TLVL_INFO) << "Done setting up message receive socket";
66 }
67 
69 {
70  TLOG(TLVL_DEBUG) << "Closing message receive socket";
71  close(message_socket_);
72  message_socket_ = -1;
73 }
74 
76 {
77  while (!stopRequested_)
78  {
79  if (message_socket_ == -1) setupMessageListener_();
80 
81  int ms_to_wait = 10;
82  struct pollfd ufds[1];
83  ufds[0].fd = message_socket_;
84  ufds[0].events = POLLIN | POLLPRI | POLLERR;
85  int rv = poll(ufds, 1, ms_to_wait);
86 
87  // Continue loop if no message received or message does not have correct event ID
88  if (rv <= 0 || (ufds[0].revents != POLLIN && ufds[0].revents != POLLPRI))
89  {
90  if (rv == 1 && (ufds[0].revents & (POLLNVAL | POLLERR | POLLHUP)))
91  {
92  close(message_socket_);
93  message_socket_ = -1;
94  }
95  if (stopRequested_)
96  {
97  break;
98  }
99  continue;
100  }
101 
102  char buffer[TRACE_STREAMER_MSGMAX + 1];
103  auto packetSize = read(message_socket_, &buffer, TRACE_STREAMER_MSGMAX);
104  if (packetSize < 0)
105  {
106  TLOG(TLVL_ERROR) << "Error receiving message, errno=" << errno << " (" << strerror(errno) << ")";
107  }
108  else
109  {
110  TLOG(TLVL_TRACE) << "Recieved message; validating...(packetSize=" << packetSize << ")";
111  std::string message(buffer, buffer + packetSize);
112  if (validate_packet(message))
113  {
114  TLOG(TLVL_TRACE) << "Valid UDP Message received! Sending to GUI!";
115  emit NewMessage(read_msg(message));
116  }
117  }
118  }
119  TLOG(TLVL_INFO) << "UDPReceiver shutting down!";
120 }
121 
122 std::list<std::string> mfviewer::UDPReceiver::tokenize_(std::string const& input)
123 {
124  size_t pos = 0;
125  std::list<std::string> output;
126 
127  while (pos != std::string::npos && pos < input.size())
128  {
129  auto newpos = input.find('|', pos);
130  if (newpos != std::string::npos)
131  {
132  output.emplace_back(input, pos, newpos - pos);
133  //TLOG(TLVL_TRACE) << "tokenize_: " << output.back();
134  pos = newpos + 1;
135  }
136  else
137  {
138  output.emplace_back(input, pos);
139  //TLOG(TLVL_TRACE) << "tokenize_: " << output.back();
140  pos = newpos;
141  }
142  }
143  return output;
144 }
145 
147 {
148  std::string hostname, category, application, message, hostaddr, file, line, module, eventID;
149  mf::ELseverityLevel sev;
150  timeval tv = {0, 0};
151  int pid = 0;
152  int seqNum = 0;
153 
154  TLOG(TLVL_TRACE) << "Recieved MF/Syslog message with contents: " << input;
155 
156  auto tokens = tokenize_(input);
157  auto it = tokens.begin();
158 
159  if (it != tokens.end())
160  {
161  bool timestamp_found = false;
162  struct tm tm;
163  time_t t;
164  while (it != tokens.end() && !timestamp_found)
165  {
166  std::string thisString = *it;
167  while (thisString.size() > 0 && !timestamp_found)
168  {
169  auto pos = thisString.find_first_of("0123456789");
170  if (pos != std::string::npos)
171  {
172  thisString = thisString.erase(0, pos);
173  //TLOG(TLVL_TRACE) << "thisString: " << thisString;
174 
175  if (strptime(thisString.c_str(), "%d-%b-%Y %H:%M:%S", &tm) != NULL)
176  {
177  timestamp_found = true;
178  break;
179  }
180 
181  if (thisString.size() > 0)
182  thisString = thisString.erase(0, 1);
183  }
184  }
185  ++it;
186  }
187 
188  tm.tm_isdst = -1;
189  t = mktime(&tm);
190  tv.tv_sec = t;
191  tv.tv_usec = 0;
192 
193  auto prevIt = it;
194  try
195  {
196  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
197  {
198  seqNum = std::stoi(*it);
199  }
200  }
201  catch (const std::invalid_argument& e)
202  {
203  it = prevIt;
204  }
205  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
206  {
207  hostname = *it;
208  }
209  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
210  {
211  hostaddr = *it;
212  }
213  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
214  {
215  sev = mf::ELseverityLevel(*it);
216  }
217  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
218  {
219  category = *it;
220  }
221  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
222  {
223  application = *it;
224  }
225  prevIt = it;
226  try
227  {
228  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
229  {
230  pid = std::stol(*it);
231  }
232  }
233  catch (const std::invalid_argument& e)
234  {
235  it = prevIt;
236  }
237  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
238  {
239  eventID = *it;
240  }
241  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
242  {
243  module = *it;
244  }
245  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
246  {
247  file = *it;
248  }
249  if (it != tokens.end() && ++it != tokens.end() /* Advances it */)
250  {
251  line = *it;
252  }
253  std::ostringstream oss;
254  bool first = true;
255  while (it != tokens.end() && ++it != tokens.end() /* Advances it */)
256  {
257  if (!first)
258  {
259  oss << "|";
260  }
261  else
262  {
263  first = false;
264  }
265  oss << *it;
266  }
267  TLOG(TLVL_TRACE) << "Message content: " << oss.str();
268  message = oss.str();
269  }
270 
271  qt_mf_msg msg(hostname, category, application, pid, tv);
272  msg.setSeverity(sev);
273  msg.setMessage("UDPMessage", seqNum, message);
274  msg.setHostAddr(hostaddr);
275  msg.setFileName(file);
276  msg.setLineNumber(line);
277  msg.setModule(module);
278  msg.setEventID(eventID);
279  msg.updateText();
280 
281  return msg;
282 }
283 
285 {
286  // Run some checks on the input packet
287  if (input.find("MF") == std::string::npos)
288  {
289  TLOG(TLVL_WARNING) << "Failed to find \"MF\" in message: " << input;
290  return false;
291  }
292  if (input.find("|") == std::string::npos)
293  {
294  TLOG(TLVL_WARNING) << "Failed to find | separator character in message: " << input;
295  return false;
296  }
297  return true;
298 }
299 
300 #include "moc_UDP_receiver.cpp"
301 
302 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:75
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:12
UDPReceiver(fhicl::ParameterSet pset)
UDPReceiver Constructor
Definition: UDP_receiver.cc:10
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:68
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