otsdaq_utilities  v2_04_01
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 // get sockaddr, IPv4 or IPv6:
46 void* get_in_addr(struct sockaddr* sa)
47 {
48  if(sa->sa_family == AF_INET)
49  {
50  return &(((struct sockaddr_in*)sa)->sin_addr);
51  }
52 
53  return &(((struct sockaddr_in6*)sa)->sin6_addr);
54 }
55 
56 int makeSocket(const char* ip, int port, struct addrinfo*& p)
57 {
58  int sockfd;
59  struct addrinfo hints, *servinfo;
60  int rv;
61  int numbytes;
62  struct sockaddr_storage their_addr;
63  socklen_t addr_len;
64  char s[INET6_ADDRSTRLEN];
65 
66  memset(&hints, 0, sizeof hints);
67  hints.ai_family = AF_UNSPEC;
68  hints.ai_socktype = SOCK_DGRAM;
69  char portStr[10];
70  sprintf(portStr, "%d", port);
71  if((rv = getaddrinfo(ip, portStr, &hints, &servinfo)) != 0)
72  {
73  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
74  return 1;
75  }
76 
77  // loop through all the results and make a socket
78  for(p = servinfo; p != NULL; p = p->ai_next)
79  {
80  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
81  {
82  perror("sw: socket");
83  continue;
84  }
85 
86  break;
87  }
88 
89  if(p == NULL)
90  {
91  fprintf(stderr, "sw: failed to create socket\n");
92  return 2;
93  }
94 
95  freeaddrinfo(servinfo);
96 
97  return sockfd;
98 }
99 
100 int main(int argc, char** argv)
101 {
102  std::cout << "\n\n" << __FILE__ << "\tStarting...\n\n" << std::endl;
103 
104  std::string myPort_("3000"); // set default
105  std::string myFwdPort_("3001"); // set default
106  std::string myFwdIP_("127.0.0.1"); // set default
107  if(argc >= 2)
108  {
109  std::cout << "\n\n"
110  << __FILE__ << "\t port parameter file:" << argv[1] << "\n\n"
111  << std::endl;
112  FILE* fp = fopen(argv[1], "r");
113  if(fp)
114  {
115  char tmp[100];
116  char tmpParamStr[100];
117  fgets(tmp, 100, fp);
118  sscanf(tmp, "%*s %s", tmpParamStr);
119  myPort_ = tmpParamStr;
120  fgets(tmp, 100, fp);
121  sscanf(tmp, "%*s %s", tmpParamStr);
122  myFwdPort_ = tmpParamStr;
123  fgets(tmp, 100, fp);
124  sscanf(tmp, "%*s %s", tmpParamStr);
125  myFwdIP_ = tmpParamStr;
126  fclose(fp);
127  }
128  else // else use defaults
129  std::cout << "\n\n"
130  << __FILE__ << "\t port parameter file failed to open: " << argv[1]
131  << "\n\n"
132  << std::endl;
133  }
134  std::cout << "\n\n"
135  << __FILE__ << "\t Forwarding from: " << myPort_ << " to: " << myFwdIP_
136  << ":" << myFwdPort_ << "\n\n"
137  << std::endl;
138 
139  int myFwdPort;
140  sscanf(myFwdPort_.c_str(), "%d", &myFwdPort);
141 
142  int sockfd;
143  int sendSockfd = 0;
144 
145  struct addrinfo hints, *servinfo, *p;
146  int rv;
147  int numbytes;
148  struct sockaddr_storage their_addr;
149  char buff[MAXBUFLEN];
150  socklen_t addr_len;
151  char s[INET6_ADDRSTRLEN];
152 
153  memset(&hints, 0, sizeof hints);
154  hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
155  hints.ai_socktype = SOCK_DGRAM;
156  hints.ai_flags = AI_PASSIVE; // use my IP
157 
158  if((rv = getaddrinfo(NULL, myPort_.c_str(), &hints, &servinfo)) != 0)
159  {
160  fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
161  return 1;
162  }
163 
164  // loop through all the results and bind to the first we can
165  for(p = servinfo; p != NULL; p = p->ai_next)
166  {
167  if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
168  {
169  perror("listener: socket");
170  continue;
171  }
172 
173  if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1)
174  {
175  close(sockfd);
176  perror("listener: bind");
177  continue;
178  }
179 
180  break;
181  }
182 
183  if(p == NULL)
184  {
185  fprintf(stderr, "listener: failed to bind socket\n");
186  return 2;
187  }
188 
189  freeaddrinfo(servinfo);
190 
194 
195  // hardware "registers"
196  uint64_t data_gen_cnt = 0;
197  uint64_t data_gen_rate = 1 << 16;
198  uint8_t dataEnabled = 0;
199 
200  const unsigned int RX_ADDR_OFFSET = 2;
201  const unsigned int RX_DATA_OFFSET = 10;
202  const unsigned int TX_DATA_OFFSET = 2;
203 
204  unsigned int packetSz;
205 
206  // for timeout/select
207  struct timeval tv;
208  fd_set readfds, masterfds;
209  tv.tv_sec = 0;
210  tv.tv_usec = 500000;
211  FD_ZERO(&masterfds);
212  FD_SET(sockfd, &masterfds);
213 
214  time_t count = 0;
215 
216  int mf_p, mf_i, mf_j; // for extracting message
217  const int MF_POS_OF_TYPE = 5;
218  const int MF_POS_OF_MSG = 11;
219  bool firstPartPresent;
220 
221  // this should ip/port of Console xdaq app Receiver port
222  sendSockfd = makeSocket(myFwdIP_.c_str(), myFwdPort, p);
223 
224  while(1)
225  {
226  readfds = masterfds; // copy to reset timeout select
227  select(sockfd + 1, &readfds, NULL, NULL, &tv);
228 
229  if(FD_ISSET(sockfd, &readfds))
230  {
231  // packet received
232  // cout << "hw: Line " << __LINE__ << ":::" << "Packet Received!" << endl;
233 
234  addr_len = sizeof their_addr;
235  if((numbytes = recvfrom(sockfd,
236  buff,
237  MAXBUFLEN - 1,
238  0,
239  (struct sockaddr*)&their_addr,
240  &addr_len)) == -1)
241  {
242  perror("recvfrom");
243  exit(1);
244  }
245 
246  // printf("hw: got packet from %s\n",
247  // inet_ntop(their_addr.ss_family,
248  // get_in_addr((struct sockaddr *)&their_addr),
249  // s, sizeof s));
250  // printf("hw: packet is %d bytes long\n", numbytes);
251  // printf("packet contents: ");
252  //
253  // for(int i=0;i<numbytes;++i)
254  // {
255  // if((i-RX_ADDR_OFFSET)%8==0) printf("\n");
256  // printf("%2.2X", (unsigned char)buff[i]);
257  // }
258  // printf("\n");
259 
260  // print message without decoration
261  // find position of message and save to p
262  // by jumping to the correct '|' marker
263  buff[numbytes] = '\0'; // make sure it is null terminated
264 
265  // DEBUG -- for indentifying strange MessageFacility bug with clipped messages
266  // std::cout << "+" << ((int)strlen(buff)==numbytes?1:0) << " " << buff <<
267  // std::endl; if((int)strlen(buff)!=numbytes)
268  // {
269  // for(int iii=strlen(buff)-3;iii<numbytes;++iii)
270  // std::cout << (int)buff[iii] << "-" << (char)buff[iii] << "
271  //"; std::cout << numbytes << " " << strlen(buff) << std::endl;
272  // std::cout << std::endl;
273  // }
274 
275  // count markers to find message
276 
277  // std::cout << "|||" << buff << std::endl; // show all
278 
279  for(mf_p = 0, mf_i = 0; mf_i < numbytes && mf_p < MF_POS_OF_TYPE; ++mf_i)
280  if(buff[mf_i] == '|')
281  ++mf_p; // count markers
282 
283  for(mf_j = mf_i; mf_j < numbytes && mf_p < MF_POS_OF_TYPE + 1; ++mf_j)
284  if(buff[mf_j] == '|')
285  ++mf_p; // count markers
286 
287  // print first part (message type)
288  if(mf_i < mf_j && mf_j < numbytes)
289  {
290  buff[mf_j - 1] = '\0';
291  std::cout << &buff[mf_i - 1];
292 
293  // tab for all types but Warning
294  if(strcmp(&buff[mf_i - 1], "|Warning") != 0)
295  std::cout << "\t";
296 
297  firstPartPresent = true;
298  }
299  else
300  firstPartPresent = false;
301 
302  for(mf_i = mf_j; mf_i < numbytes && mf_p < MF_POS_OF_MSG; ++mf_i)
303  if(buff[mf_i] == '|')
304  ++mf_p; // count markers
305 
306  // print second part
307  if(mf_i < numbytes) // if valid find, show message
308  std::cout << &buff[mf_i - 1] << std::endl; // show msg after '|'
309  else if(firstPartPresent)
310  std::cout << std::endl;
311 
312  // forward packet onto sendSockfd
313 
314  if((numbytes = sendto(
315  sendSockfd, buff, numbytes, 0, p->ai_addr, p->ai_addrlen)) == -1)
316  {
317  perror("hw: sendto");
318  exit(1);
319  }
320  // printf("hw: sent %d bytes on\n", numbytes);
321  }
322  else
323  sleep(1); // one second
324  }
325 
326  close(sockfd);
327  close(sendSockfd);
328 
329  return 0;
330 }