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