This is Unofficial EPICS BASE Doxygen Site
casw.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 
10 /*
11  *
12  * L O S A L A M O S
13  * Los Alamos National Laboratory
14  * Los Alamos, New Mexico 87545
15  *
16  * Copyright, 1986, The Regents of the University of California.
17  *
18  * Author: Jeff Hill
19  */
20 
21 #include <stdio.h>
22 
23 #define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
24 
25 #include "envDefs.h"
26 #include "errlog.h"
27 #include "osiWireFormat.h"
28 
29 #include "bhe.h"
30 #include "udpiiu.h"
31 #include "inetAddrID.h"
32 
33 // using a wrapper class around the free list avoids
34 // Tornado 2.0.1 GNU compiler bugs
36 public:
38  void * allocate ( size_t );
39  void release ( void * );
40 private:
42  bheFreeStoreMgr ( const bheFreeStoreMgr & );
43  bheFreeStoreMgr & operator = ( const bheFreeStoreMgr & );
44 };
45 
46 void * bheFreeStoreMgr::allocate ( size_t size )
47 {
48  return freeList.allocate ( size );
49 }
50 
51 void bheFreeStoreMgr::release ( void * pCadaver )
52 {
53  freeList.release ( pCadaver );
54 }
55 
56 int main ( int argc, char ** argv )
57 {
59  epicsGuard < epicsMutex > guard ( mutex );
60  bheFreeStoreMgr bheFreeList;
61  epicsTime programBeginTime = epicsTime::getCurrent();
62  bool validCommandLine = false;
63  unsigned interest = 0u;
64  SOCKET sock;
65  osiSockAddr addr;
66  osiSocklen_t addrSize;
67  char buf [0x4000];
68  const char *pCurBuf;
69  const caHdr *pCurMsg;
70  ca_uint16_t serverPort;
71  ca_uint16_t repeaterPort;
72  int status;
73 
74  if ( argc == 1 ) {
75  validCommandLine = true;
76  }
77  else if ( argc == 2 ) {
78  status = sscanf ( argv[1], " -i%u ", & interest );
79  if ( status == 1 ) {
80  validCommandLine = true;
81  }
82  }
83  else if ( argc == 3 ) {
84  if ( strcmp ( argv[1], "-i" ) == 0 ) {
85  status = sscanf ( argv[2], " %u ", & interest );
86  if ( status == 1 ) {
87  validCommandLine = true;
88  }
89  }
90  }
91 
92  if ( ! validCommandLine ) {
93  printf ( "usage: casw <-i interestLevel>\n" );
94  return 0;
95  }
96 
97  serverPort =
99  static_cast <unsigned short> (CA_SERVER_PORT) );
100 
101  repeaterPort =
103  static_cast <unsigned short> (CA_REPEATER_PORT) );
104 
105  caStartRepeaterIfNotInstalled ( repeaterPort );
106 
107  sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
108  if ( sock == INVALID_SOCKET ) {
109  char sockErrBuf[64];
111  sockErrBuf, sizeof ( sockErrBuf ) );
112  errlogPrintf ("casw: unable to create datagram socket because = \"%s\"\n",
113  sockErrBuf );
114  return -1;
115  }
116 
117  memset ( (char *) &addr, 0 , sizeof (addr) );
118  addr.ia.sin_family = AF_INET;
119  addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
120  addr.ia.sin_port = htons ( 0 ); // any port
121  status = bind ( sock, &addr.sa, sizeof (addr) );
122  if ( status < 0 ) {
123  char sockErrBuf[64];
125  sockErrBuf, sizeof ( sockErrBuf ) );
126  epicsSocketDestroy ( sock );
127  errlogPrintf ( "casw: unable to bind to an unconstrained address because = \"%s\"\n",
128  sockErrBuf );
129  return -1;
130  }
131 
132  osiSockIoctl_t yes = true;
133  status = socket_ioctl ( sock, FIONBIO, &yes );
134  if ( status < 0 ) {
135  char sockErrBuf[64];
137  sockErrBuf, sizeof ( sockErrBuf ) );
138  epicsSocketDestroy ( sock );
139  errlogPrintf ( "casw: unable to set socket to nonblocking state because \"%s\"\n",
140  sockErrBuf );
141  return -1;
142  }
143 
144  unsigned attemptNumber = 0u;
145  while ( true ) {
146  caRepeaterRegistrationMessage ( sock, repeaterPort, attemptNumber );
147  epicsThreadSleep ( 0.1 );
148  addrSize = ( osiSocklen_t ) sizeof ( addr );
149  status = recvfrom ( sock, buf, sizeof ( buf ), 0,
150  &addr.sa, &addrSize );
151  if ( status >= static_cast <int> ( sizeof ( *pCurMsg ) ) ) {
152  pCurMsg = reinterpret_cast < caHdr * > ( buf );
154  if ( cmmd == REPEATER_CONFIRM ) {
155  break;
156  }
157  }
158 
159  attemptNumber++;
160  if ( attemptNumber > 100 ) {
161  epicsSocketDestroy ( sock );
162  errlogPrintf ( "casw: unable to register with the CA repeater\n" );
163  return -1;
164  }
165  }
166 
167  osiSockIoctl_t no = false;
168  status = socket_ioctl ( sock, FIONBIO, &no );
169  if ( status < 0 ) {
170  char sockErrBuf[64];
172  sockErrBuf, sizeof ( sockErrBuf ) );
173  epicsSocketDestroy ( sock );
174  errlogPrintf ( "casw: unable to set socket to blocking state because \"%s\"\n",
175  sockErrBuf );
176  return -1;
177  }
178 
179  resTable < bhe, inetAddrID > beaconTable;
180  while ( true ) {
181 
182  addrSize = ( osiSocklen_t ) sizeof ( addr );
183  status = recvfrom ( sock, buf, sizeof ( buf ), 0,
184  &addr.sa, &addrSize );
185  if ( status <= 0 ) {
186  char sockErrBuf[64];
188  sockErrBuf, sizeof ( sockErrBuf ) );
189  epicsSocketDestroy ( sock );
190  errlogPrintf ("casw: error from recv was = \"%s\"\n",
191  sockErrBuf );
192  return -1;
193  }
194 
195  if ( addr.sa.sa_family != AF_INET ) {
196  continue;
197  }
198 
199  unsigned byteCount = static_cast <unsigned> ( status );
200  pCurMsg = reinterpret_cast < const caHdr * > ( ( pCurBuf = buf ) );
201  while ( byteCount ) {
202  AlignedWireRef < const epicsUInt16 > pstSize ( pCurMsg->m_postsize );
203  size_t msgSize = pstSize + sizeof ( *pCurMsg ) ;
204  if ( msgSize > byteCount ) {
205  errlogPrintf ( "CASW: udp input protocol violation\n" );
206  break;
207  }
208 
209  epicsUInt16 cmmd = AlignedWireRef < const epicsUInt16 > ( pCurMsg->m_cmmd );
210  if ( cmmd == CA_PROTO_RSRV_IS_UP ) {
211  bool anomaly = false;
212  epicsTime previousTime;
213  struct sockaddr_in ina;
214 
215  /*
216  * this allows a fan-out server to potentially
217  * insert the true address of the CA server
218  *
219  * old servers:
220  * 1) set this field to one of the ip addresses of the host _or_
221  * 2) set this field to INADDR_ANY
222  * new servers:
223  * always set this field to INADDR_ANY
224  *
225  * clients always assume that if this
226  * field is set to something that isnt INADDR_ANY
227  * then it is the overriding IP address of the server.
228  */
229  ina.sin_family = AF_INET;
230  ina.sin_addr.s_addr = pCurMsg->m_available;
231 
232  if ( pCurMsg->m_count != 0 ) {
233  ina.sin_port = pCurMsg->m_count;
234  }
235  else {
236  /*
237  * old servers dont supply this and the
238  * default port must be assumed
239  */
240  ina.sin_port = htons ( serverPort );
241  }
242 
243  ca_uint32_t beaconNumber = ntohl ( pCurMsg->m_cid );
244  unsigned protocolRevision = ntohs ( pCurMsg->m_dataType );
245 
246  epicsTime currentTime = epicsTime::getCurrent();
247 
248  /*
249  * look for it in the hash table
250  */
251  bhe *pBHE = beaconTable.lookup ( ina );
252  if ( pBHE ) {
253  previousTime = pBHE->updateTime ( guard );
254  anomaly = pBHE->updatePeriod (
255  guard, programBeginTime,
256  currentTime, beaconNumber, protocolRevision );
257  }
258  else {
259  /*
260  * This is the first beacon seen from this server.
261  * Wait until 2nd beacon is seen before deciding
262  * if it is a new server (or just the first
263  * time that we have seen a server's beacon
264  * shortly after the program started up)
265  */
266  pBHE = new ( bheFreeList )
267  bhe ( mutex, currentTime, beaconNumber, ina );
268  if ( pBHE ) {
269  if ( beaconTable.add ( *pBHE ) < 0 ) {
270  pBHE->~bhe ();
271  bheFreeList.release ( pBHE );
272  }
273  }
274  }
275  if ( anomaly || interest > 1 ) {
276  char date[64];
277  currentTime.strftime ( date, sizeof ( date ),
278  "%Y-%m-%d %H:%M:%S.%09f");
279  char host[64];
280  ipAddrToA ( &ina, host, sizeof ( host ) );
281  const char * pPrefix = "";
282  if ( interest > 1 ) {
283  if ( anomaly ) {
284  pPrefix = "* ";
285  }
286  else {
287  pPrefix = " ";
288  }
289  }
290  printf ( "%s%-40s %s\n",
291  pPrefix, host, date );
292  if ( anomaly && interest > 0 ) {
293  printf ( "\testimate=%f current=%f\n",
294  pBHE->period ( guard ),
295  currentTime - previousTime );
296  }
297  fflush(stdout);
298  }
299  }
300  pCurBuf += msgSize;
301  pCurMsg = reinterpret_cast < const caHdr * > ( pCurBuf );
302  byteCount -= msgSize;
303  }
304  }
305 }
#define CA_REPEATER_PORT
Definition: caProto.h:54
bheFreeStoreMgr()
Definition: casw.cpp:37
LIBCOM_API void epicsStdCall epicsSocketDestroy(SOCKET s)
Definition: osdSock.c:117
void * allocate(size_t)
Definition: casw.cpp:46
#define INVALID_SOCKET
Definition: osdSock.h:32
pvd::Status status
int osiSocklen_t
Definition: osdSock.h:36
struct sockaddr sa
Definition: osiSock.h:158
int add(T &res)
Definition: resourceLib.h:643
unsigned short epicsUInt16
Definition: epicsTypes.h:41
struct sockaddr_in ia
Definition: osiSock.h:157
Routines to get and set EPICS environment parameters.
#define printf
Definition: epicsStdio.h:41
unsigned int ca_uint32_t
Definition: caProto.h:76
LIBCA_API bool updatePeriod(epicsGuard< epicsMutex > &, const epicsTime &programBeginTime, const epicsTime &currentTime, ca_uint32_t beaconNumber, unsigned protocolRevision)
Definition: bhe.cpp:124
#define CA_SERVER_PORT
Definition: caProto.h:53
int main(int argc, char **argv)
Definition: casw.cpp:56
unsigned short ca_uint16_t
Definition: caProto.h:75
T * lookup(const ID &idIn) const
Definition: resourceLib.h:342
LIBCA_API ~bhe()
Definition: bhe.cpp:62
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
LIBCA_API epicsTime updateTime(epicsGuard< epicsMutex > &) const
Definition: bhe.cpp:308
#define socket_ioctl(A, B, C)
Definition: osdSock.h:34
LIBCOM_API SOCKET epicsStdCall epicsSocketCreate(int domain, int type, int protocol)
Definition: osdSock.c:71
ca_uint16_t m_cmmd
Definition: caProto.h:161
LIBCOM_API const ENV_PARAM EPICS_CA_SERVER_PORT
int osiSockIoctl_t
Definition: osdSock.h:35
epicsMutex mutex
Definition: pvAccess.cpp:71
void epicsStdCall caStartRepeaterIfNotInstalled(unsigned repeaterPort)
Definition: udpiiu.cpp:581
LIBCOM_API const ENV_PARAM EPICS_CA_REPEATER_PORT
LIBCOM_API unsigned short epicsStdCall envGetInetPortConfigParam(const ENV_PARAM *pEnv, unsigned short defaultPort)
Get value of a port number configuration parameter.
Definition: envSubr.c:398
void release(void *)
Definition: casw.cpp:51
Definition: bhe.h:45
int SOCKET
Definition: osdSock.h:31
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
#define stdout
Definition: epicsStdio.h:30
#define REPEATER_CONFIRM
Definition: caProto.h:100
void date(const char *format)
void * allocate(size_t size)
Definition: tsFreeList.h:126
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
void release(void *p)
Definition: tsFreeList.h:176
unsigned epicsStdCall ipAddrToA(const struct sockaddr_in *paddr, char *pBuf, unsigned bufSize)
Definition: osiSock.c:92
LIBCA_API double period(epicsGuard< epicsMutex > &) const
Definition: bhe.cpp:302
void epicsStdCall caRepeaterRegistrationMessage(SOCKET sock, unsigned repeaterPort, unsigned attemptNumber)
Definition: udpiiu.cpp:464
#define CA_PROTO_RSRV_IS_UP
Definition: caProto.h:96