otsdaq_utilities  v2_04_02
MF_ReceiveAndForward.cpp
1 // MF_ReceiveAndForward.cpp
2 // by rrivera at fnal dot gov
3 // created Feb 2016
4 //
5 // This is a simple UDP receive and forward program
6 // for MessageFacility packets.
7 //
8 // It echos packets received and only appends '|' as decoration.
9 //
10 //
11 //
12 //
13 // compile with:
14 // g++ MF_ReceiveAndForward.cpp -o MF_ReceiveAndForward.o
15 //
16 // if developing, consider appending -D_GLIBCXX_DEBUG to get more
17 // descriptive error messages
18 //
19 // run with:
20 //./MF_ReceiveAndForward.o <optional port file name>
21 //
22 //
23 // Port Config File Format:
24 // RECEIVING_PORT <port number>
25 // FORWARDING_PORT <port number>
26 //
27 //
28 
29 #include <arpa/inet.h>
30 #include <errno.h>
31 #include <netdb.h>
32 #include <netinet/in.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/socket.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <iostream>
40 
41 using namespace std;
42 
43 #define MAXBUFLEN 5000
44 
45 #define __MF_SUBJECT__ "mfReceiveAndForward"
46 #define Q(X) #X
47 #define QUOTE(X) Q(X)
48 
49 // take filename only after srcs/ (this gives by repo name)
50 #define __SHORTFILE__ \
51  (strstr(&__FILE__[0], "/srcs/") ? strstr(&__FILE__[0], "/srcs/") + 6 : __FILE__)
52 
53 // take only file name
54 #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
55 
56 #define __E__ std::endl
57 
58 #define __COUT_HDR_F__ __SHORTFILE__ << "\t"
59 #define __COUT_HDR_L__ "[" << std::dec << __LINE__ << "]\t"
60 #define __COUT_HDR_P__ __PRETTY_FUNCTION__ << "\t"
61 #define __COUT_HDR_FL__ __SHORTFILE__ << " " << __COUT_HDR_L__
62 #define __COUT_HDR_FP__ __SHORTFILE__ << " : " << __COUT_HDR_P__
63 #define __COUT_HDR__ __COUT_HDR_FL__
64 
65 #define __COUT_TYPE__(X) std::cout << QUOTE(X) << ":" << __MF_SUBJECT__ << ":"
66 
67 #define __COUT_ERR__ __COUT_TYPE__(LogError) << __COUT_HDR__
68 #define __COUT_WARN__ __COUT_TYPE__(LogWarning) << __COUT_HDR__
69 #define __COUT_INFO__ __COUT_TYPE__(LogInfo) << __COUT_HDR__
70 #define __COUT__ __COUT_TYPE__(LogDebug) << __COUT_HDR__
71 #define __COUTV__(X) __COUT__ << QUOTE(X) << " = " << X << __E__
72 
73 // get sockaddr, IPv4 or IPv6:
74 void* get_in_addr(struct sockaddr* sa)
75 {
76  if(sa->sa_family == AF_INET)
77  {
78  return &(((struct sockaddr_in*)sa)->sin_addr);
79  }
80 
81  return &(((struct sockaddr_in6*)sa)->sin6_addr);
82 }
83 
84 int makeSocket(const char* ip, int port, struct addrinfo*& p)
85 {
86  int sockfd;
87  struct addrinfo hints, *servinfo;
88  int rv;
89  int numbytes;
90  struct sockaddr_storage their_addr;
91  socklen_t addr_len;
92  char s[INET6_ADDRSTRLEN];
93 
94  memset(&hints, 0, sizeof hints);
95  hints.ai_family = AF_UNSPEC;
96  hints.ai_socktype = SOCK_DGRAM;
97  char portStr[10];
98  sprintf(portStr, "%d", port);
99  if((rv = getaddrinfo(ip, portStr, &hints, &servinfo)) != 0)
100  {
101  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
102  return 1;
103  }
104 
105  // loop through all the results and make a socket
106  for(p = servinfo; p != NULL; p = p->ai_next)
107  {
108  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
109  {
110  perror("sw: socket");
111  continue;
112  }
113 
114  break;
115  }
116 
117  if(p == NULL)
118  {
119  fprintf(stderr, "sw: failed to create socket\n");
120  return 2;
121  }
122 
123  freeaddrinfo(servinfo);
124 
125  return sockfd;
126 }
127 
128 int main(int argc, char** argv)
129 {
130  __COUT__ << "Starting...\n\n" << __E__;
131 
132  std::string myPort_("3000"); // set default
133  std::string myFwdPort_("3001"); // set default
134  std::string myFwdIP_("127.0.0.1"); // set default
135  if(argc >= 2)
136  {
137  __COUT__ << "port parameter file:" << argv[1] << "\n\n" << __E__;
138  FILE* fp = fopen(argv[1], "r");
139  if(fp)
140  {
141  char tmp[100];
142  char tmpParamStr[100];
143  fgets(tmp, 100, fp);
144  sscanf(tmp, "%*s %s", tmpParamStr);
145  myPort_ = tmpParamStr;
146  fgets(tmp, 100, fp);
147  sscanf(tmp, "%*s %s", tmpParamStr);
148  myFwdPort_ = tmpParamStr;
149  fgets(tmp, 100, fp);
150  sscanf(tmp, "%*s %s", tmpParamStr);
151  myFwdIP_ = tmpParamStr;
152  fclose(fp);
153  }
154  else // else use defaults
155  __COUT__ << "port parameter file failed to open: " << argv[1] << "\n\n"
156  << __E__;
157  }
158  __COUT__ << "Forwarding from: " << myPort_ << " to: " << myFwdIP_ << ":" << myFwdPort_
159  << "\n\n"
160  << __E__;
161 
162  int myFwdPort;
163  sscanf(myFwdPort_.c_str(), "%d", &myFwdPort);
164 
165  int sockfd;
166  int sendSockfd = 0;
167 
168  struct addrinfo hints, *servinfo, *p;
169  int rv;
170  int numbytes;
171  struct sockaddr_storage their_addr;
172  char buff[MAXBUFLEN];
173  socklen_t addr_len;
174  char s[INET6_ADDRSTRLEN];
175 
176  memset(&hints, 0, sizeof hints);
177  hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
178  hints.ai_socktype = SOCK_DGRAM;
179  hints.ai_flags = AI_PASSIVE; // use my IP
180 
181  if((rv = getaddrinfo(NULL, myPort_.c_str(), &hints, &servinfo)) != 0)
182  {
183  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
184  return 1;
185  }
186 
187  // loop through all the results and bind to the first we can
188  for(p = servinfo; p != NULL; p = p->ai_next)
189  {
190  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
191  {
192  __COUT__ << "listener: socket...\n\n" << __E__;
193  perror("listener: socket");
194  continue;
195  }
196 
197  if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1)
198  {
199  close(sockfd);
200  __COUT__ << "listener: bind.\n\n" << __E__;
201  perror("listener: bind");
202  continue;
203  }
204 
205  break;
206  }
207 
208  if(p == NULL)
209  {
210  __COUT__ << "listener: failed to bind socket...\n\n" << __E__;
211  fprintf(stderr, "listener: failed to bind socket\n");
212  return 2;
213  }
214 
215  freeaddrinfo(servinfo);
216 
220 
221  // hardware "registers"
222  uint64_t data_gen_cnt = 0;
223  uint64_t data_gen_rate = 1 << 16;
224  uint8_t dataEnabled = 0;
225 
226  const unsigned int RX_ADDR_OFFSET = 2;
227  const unsigned int RX_DATA_OFFSET = 10;
228  const unsigned int TX_DATA_OFFSET = 2;
229 
230  unsigned int packetSz;
231 
232  // for timeout/select
233  struct timeval tv;
234  fd_set readfds, masterfds;
235  tv.tv_sec = 0;
236  tv.tv_usec = 500000;
237  FD_ZERO(&masterfds);
238  FD_SET(sockfd, &masterfds);
239 
240  time_t count = 0;
241 
242  int mf_p, mf_i, mf_j; // for extracting message
243  const int MF_POS_OF_TYPE = 5;
244  const int MF_POS_OF_MSG = 11;
245  bool firstPartPresent;
246 
247  // this should ip/port of Console xdaq app Receiver port
248  sendSockfd = makeSocket(myFwdIP_.c_str(), myFwdPort, p);
249 
250  while(1)
251  {
252  readfds = masterfds; // copy to reset timeout select
253  select(sockfd + 1, &readfds, NULL, NULL, &tv);
254 
255  if(FD_ISSET(sockfd, &readfds))
256  {
257  // packet received
258  // cout << "hw: Line " << __LINE__ << ":::" << "Packet Received!" << endl;
259 
260  addr_len = sizeof their_addr;
261  if((numbytes = recvfrom(sockfd,
262  buff,
263  MAXBUFLEN - 1,
264  0,
265  (struct sockaddr*)&their_addr,
266  &addr_len)) == -1)
267  {
268  __COUT__ << "error: recvfrom...\n\n" << __E__;
269  perror("recvfrom");
270  exit(1);
271  }
272 
273  // printf("hw: got packet from %s\n",
274  // inet_ntop(their_addr.ss_family,
275  // get_in_addr((struct sockaddr *)&their_addr),
276  // s, sizeof s));
277  // printf("hw: packet is %d bytes long\n", numbytes);
278  // printf("packet contents: ");
279  //
280  // for(int i=0;i<numbytes;++i)
281  // {
282  // if((i-RX_ADDR_OFFSET)%8==0) printf("\n");
283  // printf("%2.2X", (unsigned char)buff[i]);
284  // }
285  // printf("\n");
286 
287  // print message without decoration
288  // find position of message and save to p
289  // by jumping to the correct '|' marker
290  buff[numbytes] = '\0'; // make sure it is null terminated
291 
292  // DEBUG -- for identifying strange MessageFacility bug with clipped messages
293  // std::cout << "+" << ((int)strlen(buff)==numbytes?1:0) << " " << buff <<
294  // __E__; if((int)strlen(buff)!=numbytes)
295  // {
296  // for(int iii=strlen(buff)-3;iii<numbytes;++iii)
297  // std::cout << (int)buff[iii] << "-" << (char)buff[iii] << "
298  //"; std::cout << numbytes << " " << strlen(buff) << __E__;
299  // std::cout << __E__;
300  // }
301 
302  // count markers to find message
303 
304  // std::cout << "|||" << buff << __E__; // show all
305  // e.g. UDPMFMESSAGE7370|01-Jul-2019 11:12:44
306  // CDT|3|correlator2.fnal.gov|131.225.52.45|Info|_TCPConnect|xdaq.exe|7370|Booted|DAQ|TCPConnect.cc|241|Resolving
307  // ip correlator2.fnal.gov
308 
309  for(mf_p = 0, mf_i = 0; mf_i < numbytes && mf_p < MF_POS_OF_TYPE; ++mf_i)
310  if(buff[mf_i] == '|')
311  ++mf_p; // count markers
312 
313  for(mf_j = mf_i; mf_j < numbytes && mf_p < MF_POS_OF_TYPE + 1; ++mf_j)
314  if(buff[mf_j] == '|')
315  ++mf_p; // count markers
316 
317  // print first part (message type)
318  if(mf_i < mf_j && mf_j < numbytes)
319  {
320  char sav = buff[mf_j - 1];
321  buff[mf_j - 1] = '\0';
322  std::cout << &buff[mf_i - 1];
323  buff[mf_j - 1] = sav;
324 
325  // tab for all types but Warning
326  if(strcmp(&buff[mf_i - 1], "|Warning") != 0)
327  std::cout << "\t";
328 
329  firstPartPresent = true;
330  }
331  else
332  firstPartPresent = false;
333 
334  for(mf_i = mf_j; mf_i < numbytes && mf_p < MF_POS_OF_MSG; ++mf_i)
335  if(buff[mf_i] == '|')
336  ++mf_p; // count markers
337 
338  // print second part
339  if(mf_i < numbytes) // if valid find, show message
340  std::cout << &buff[mf_i - 1] << __E__; // show msg after '|'
341  else if(firstPartPresent)
342  std::cout << __E__;
343 
344  // forward packet onto sendSockfd
345 
346  if((numbytes = sendto(
347  sendSockfd, buff, numbytes, 0, p->ai_addr, p->ai_addrlen)) == -1)
348  {
349  __COUT__ << "error: sendto...\n\n" << __E__;
350  perror("hw: sendto");
351  exit(1);
352  }
353  // printf("hw: sent %d bytes on\n", numbytes);
354  }
355  else
356  sleep(1); // one second
357  }
358 
359  close(sockfd);
360  close(sendSockfd);
361 
362  __COUT__ << "Exited.\n\n" << __E__;
363 
364  return 0;
365 }