This is Unofficial EPICS BASE Doxygen Site
caservertask.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2016 Michael Davidsaver
3 * Copyright (c) 2015 Brookhaven Science Assoc. as operator of Brookhaven
4 * National Laboratory.
5 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
6 * National Laboratory.
7 * Copyright (c) 2002 The Regents of the University of California, as
8 * Operator of Los Alamos National Laboratory.
9 * EPICS BASE is distributed subject to a Software License Agreement found
10 * in file LICENSE that is included with this distribution.
11 \*************************************************************************/
12 
13 /*
14  * Author: Jeffrey O. Hill
15  */
16 
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <limits.h>
22 #include <errno.h>
23 
24 #include "addrList.h"
25 #include "epicsEvent.h"
26 #include "epicsMutex.h"
27 #include "epicsSignal.h"
28 #include "epicsStdio.h"
29 #include "epicsTime.h"
30 #include "errlog.h"
31 #include "freeList.h"
32 #include "osiPoolStatus.h"
33 #include "osiSock.h"
34 #include "taskwd.h"
35 #include "cantProceed.h"
36 
37 #include "epicsExport.h"
38 
39 #define epicsExportSharedSymbols
40 #include "dbChannel.h"
41 #include "dbCommon.h"
42 #include "dbEvent.h"
43 #include "db_field_log.h"
44 #include "dbServer.h"
45 #include "rsrv.h"
46 
47 #define GLBLSOURCE
48 #include "server.h"
49 
51 
52 /*
53  *
54  * req_server()
55  *
56  * CA server task
57  *
58  * Waits for connections at the CA port and spawns a task to
59  * handle each of them
60  *
61  */
62 static void req_server (void *pParm)
63 {
64  rsrv_iface_config *conf = pParm;
65  SOCKET IOC_sock;
66 
68 
69  IOC_sock = conf->tcp;
70 
72 
73  while (TRUE) {
74  SOCKET clientSock;
75  osiSockAddr sockAddr;
76  osiSocklen_t addLen = sizeof(sockAddr);
77 
78  while (castcp_ctl == ctlPause) {
79  epicsThreadSleep(0.1);
80  }
81 
82  clientSock = epicsSocketAccept ( IOC_sock, &sockAddr.sa, &addLen );
83  if ( clientSock == INVALID_SOCKET ||
84  sockAddr.sa.sa_family != AF_INET ||
85  addLen < sizeof(sockAddr.ia) ) {
86  char sockErrBuf[64];
88  sockErrBuf, sizeof ( sockErrBuf ) );
89  errlogPrintf("CAS: Client accept error: %s (%d)\n",
90  sockErrBuf, (int)addLen );
91  epicsThreadSleep(15.0);
92  continue;
93  }
94  else {
95  epicsThreadId id;
96  struct client *pClient;
97 
98  /* socket passed in is closed if unsuccessful here */
99  pClient = create_tcp_client ( clientSock, &sockAddr );
100  if ( ! pClient ) {
101  epicsThreadSleep ( 15.0 );
102  continue;
103  }
104 
105  LOCK_CLIENTQ;
106  ellAdd ( &clientQ, &pClient->node );
108 
111  camsgtask, pClient );
112  if ( id == 0 ) {
113  LOCK_CLIENTQ;
114  ellDelete ( &clientQ, &pClient->node );
116  destroy_tcp_client ( pClient );
117  errlogPrintf ( "CAS: task creation for new client failed\n" );
118  epicsThreadSleep ( 15.0 );
119  continue;
120  }
121  }
122  }
123 }
124 
125 static
126 int tryBind(SOCKET sock, const osiSockAddr* addr, const char *name)
127 {
128  if(bind(sock, (struct sockaddr *) &addr->sa, sizeof(*addr))<0) {
129  char sockErrBuf[64];
131  {
133  sockErrBuf, sizeof ( sockErrBuf ) );
134  errlogPrintf ( "CAS: %s bind error: %s\n",
135  name, sockErrBuf );
137  }
138  return -1;
139  } else
140  return 0;
141 }
142 
143 /* need to collect a set of TCP sockets, one for each interface,
144  * which are bound to the same TCP port number.
145  * Needed to avoid the complications and confusion of different TCP
146  * ports for each interface (name server and beacon sender would need
147  * to know this).
148  */
149 static
150 SOCKET* rsrv_grab_tcp(unsigned short *port)
151 {
152  SOCKET *socks;
153  osiSockAddr scratch;
154  unsigned i;
155 
156  socks = mallocMustSucceed(ellCount(&casIntfAddrList)*sizeof(*socks), "rsrv_grab_tcp");
157  for(i=0; i<ellCount(&casIntfAddrList); i++)
158  socks[i] = INVALID_SOCKET;
159 
160  /* start with preferred port */
161  memset(&scratch, 0, sizeof(scratch));
162  scratch.ia.sin_family = AF_INET;
163  scratch.ia.sin_port = htons(*port);
164 
165  while(ellCount(&casIntfAddrList)>0) {
166  ELLNODE *cur, *next;
167  unsigned ok = 1;
168 
169  for(i=0; i<ellCount(&casIntfAddrList); i++) {
170  if(socks[i] != INVALID_SOCKET)
171  epicsSocketDestroy(socks[i]);
172  socks[i] = INVALID_SOCKET;
173  }
174 
175  for (i=0, cur=ellFirst(&casIntfAddrList), next = cur ? ellNext(cur) : NULL;
176  cur;
177  i++, cur=next, next=next ? ellNext(next) : NULL)
178  {
179  SOCKET tcpsock;
180  osiSockAddr ifaceAddr = ((osiSockAddrNode *)cur)->addr;
181 
182  scratch.ia.sin_addr = ifaceAddr.ia.sin_addr;
183 
184  tcpsock = socks[i] = epicsSocketCreate (AF_INET, SOCK_STREAM, 0);
185  if(tcpsock==INVALID_SOCKET)
186  cantProceed("rsrv ran out of sockets during initialization");
187 
189 
190  if(bind(tcpsock, &scratch.sa, sizeof(scratch))==0 && listen(tcpsock, 20)==0) {
191  if(scratch.ia.sin_port==0) {
192  /* use first socket to pick a random port */
193  osiSocklen_t alen = sizeof(ifaceAddr);
194  assert(i==0);
195  if(getsockname(tcpsock, &ifaceAddr.sa, &alen)) {
196  char sockErrBuf[64];
198  sockErrBuf, sizeof ( sockErrBuf ) );
199  errlogPrintf ( "CAS: getsockname error: %s\n",
200  sockErrBuf );
202  ok = 0;
203  break;
204  }
205  scratch.ia.sin_port = ifaceAddr.ia.sin_port;
206  assert(scratch.ia.sin_port!=0);
207  }
208  } else {
209  int errcode = SOCKERRNO;
210  /* bind fails. React harshly to unexpected errors to avoid an infinite loop */
211  if(errcode==SOCK_EADDRNOTAVAIL) {
212  /* this is not a bind()able address. */
213  int j;
214  char name[40];
215  ipAddrToDottedIP(&scratch.ia, name, sizeof(name));
216  printf("Skipping %s which is not an interface address\n", name);
217 
218  for(j=0; j<=i; j++) {
219  epicsSocketDestroy(socks[j]);
220  socks[j] = INVALID_SOCKET;
221  }
222 
223  ellDelete(&casIntfAddrList, cur);
224  free(cur);
225  ok = 0;
226  break;
227  }
228  /* if SOCK_EADDRINUSE or SOCK_EACCES try again with a different
229  * port number, otherwise fail hard.
230  */
231  if (errcode != SOCK_EADDRINUSE &&
232  errcode != SOCK_EACCES) {
233  char name[40];
234  char sockErrBuf[64];
236  sockErrBuf, sizeof ( sockErrBuf ) );
237  ipAddrToDottedIP(&scratch.ia, name, sizeof(name));
238  cantProceed( "CAS: Socket bind %s error: %s\n",
239  name, sockErrBuf );
240  }
241  ok = 0;
242  break;
243  }
244  }
245 
246  if (ok) {
247  assert(scratch.ia.sin_port!=0);
248  *port = ntohs(scratch.ia.sin_port);
249 
250  break;
251  } else {
252 
253  for(i=0; i<ellCount(&casIntfAddrList); i++) {
254  /* cleanup any ports actually bound */
255  if(socks[i]!=INVALID_SOCKET) {
256  epicsSocketDestroy(socks[i]);
257  socks[i] = INVALID_SOCKET;
258  }
259  }
260 
261  scratch.ia.sin_port=0; /* next iteration starts with a random port */
262  }
263  }
264 
265  if(ellCount(&casIntfAddrList)==0)
266  cantProceed("Error: RSRV has empty interface list\n"
267  "The CA server can't function without binding to"
268  " at least one network interface.\n");
269 
270  return socks;
271 }
272 
273 static
274 void rsrv_build_addr_lists(void)
275 {
276  int autobeaconlist = 1;
277 
278  /* the UDP ports are known at this point, but the TCP port is not */
280  assert(ca_udp_port!=0);
281 
283 
285  ellInit ( &beaconAddrList );
287 
288  /* Setup socket for sending server beacons.
289  * Also used for NIC introspection
290  */
291 
292  beaconSocket = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
294  cantProceed("socket allocation failed during address list expansion");
295 
296  {
297  int intTrue = 1;
298  if (setsockopt (beaconSocket, SOL_SOCKET, SO_BROADCAST,
299  (char *)&intTrue, sizeof(intTrue))<0) {
300  cantProceed("CAS: online socket set up error\n");
301  }
302 #ifdef IP_ADD_MEMBERSHIP
303  {
304  osiSockOptMcastLoop_t flag = 1;
305  if (setsockopt(beaconSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
306  (char *)&flag, sizeof(flag))<0) {
307  char sockErrBuf[64];
309  sockErrBuf, sizeof ( sockErrBuf ) );
310  errlogPrintf("CAS: failed to set mcast loopback: %s\n",
311  sockErrBuf);
312  }
313  }
314 #endif
315 
316 #ifdef IP_MULTICAST_TTL
317  {
319  long val;
321  val =1;
322  ttl = val;
323  if ( setsockopt(beaconSocket, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl))) {
324  char sockErrBuf[64];
326  sockErrBuf, sizeof ( sockErrBuf ) );
327  errlogPrintf("rsrv: failed to set mcast ttl %d\n", (int)ttl);
328  }
329  }
330 #endif
331  }
332 
333  /* populate the interface address list (default is empty) */
334  {
335  ELLLIST temp = ELLLIST_INIT;
336  /* use the first parameter which is set. */
338 
340  }
341 
342  /* Process the interface address list
343  * Move multicast addresses to casMCastAddrList
344  * Populate beacon address list (if autobeaconlist and iface list not-empty).
345  */
346  {
347  int foundWildcard = 0, doautobeacon = autobeaconlist;
348 
349  osiSockAddrNode *pNode, *pNext;
350  for(pNode = (osiSockAddrNode*)ellFirst(&casIntfAddrList),
351  pNext = pNode ? (osiSockAddrNode*)ellNext(&pNode->node) : NULL;
352  pNode;
353  pNode = pNext,
354  pNext = pNext ? (osiSockAddrNode*)ellNext(&pNext->node) : NULL)
355  {
356  osiSockAddr match;
357  epicsUInt32 top = ntohl(pNode->addr.ia.sin_addr.s_addr)>>24;
358 
359  if(pNode->addr.ia.sin_family==AF_INET && pNode->addr.ia.sin_addr.s_addr==htonl(INADDR_ANY))
360  {
361  foundWildcard = 1;
362 
363  } else if(pNode->addr.ia.sin_family==AF_INET && top>=224 && top<=239) {
364  /* This is a multi-cast address */
365  ellDelete(&casIntfAddrList, &pNode->node);
366  ellAdd(&casMCastAddrList, &pNode->node);
367  continue;
368  }
369 
370  if(!doautobeacon)
371  continue;
372  /* when given a specific interface address, auto populate with the
373  * corresponding broadcast address.
374  */
375 
376  autobeaconlist = 0; /* prevent later population from wildcard */
377 
378  memset(&match, 0, sizeof(match));
379  match.ia.sin_family = AF_INET;
380  match.ia.sin_addr.s_addr = pNode->addr.ia.sin_addr.s_addr;
381  match.ia.sin_port = htons(ca_beacon_port);
382 
384  }
385 
386  if (foundWildcard && ellCount(&casIntfAddrList) != 1) {
387  cantProceed("CAS interface address list can not contain 0.0.0.0 and other interface addresses.\n");
388  }
389  }
390 
391  if (ellCount(&casIntfAddrList) == 0) {
392  /* default to wildcard 0.0.0.0 when interface address list is empty */
393  osiSockAddrNode *pNode = (osiSockAddrNode *) callocMustSucceed( 1, sizeof(*pNode), "rsrv_init" );
394  pNode->addr.ia.sin_family = AF_INET;
395  pNode->addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY );
396  pNode->addr.ia.sin_port = 0;
397  ellAdd ( &casIntfAddrList, &pNode->node );
398  }
399 
400  {
401  ELLLIST temp = ELLLIST_INIT;
402  osiSockAddrNode *pNode;
403 
404  ellConcat(&temp, &beaconAddrList);
405 
406  /* collect user specified beacon address list
407  * prefer EPICS_CAS_BEACON_ADDR_LIST, fallback to EPICS_CA_ADDR_LIST
408  */
410 
411  if (autobeaconlist) {
412  /* auto populate with all broadcast addresses.
413  * Note that autobeaconlist is zeroed above if an interface
414  * address list is provided.
415  */
416  osiSockAddr match;
417  memset(&match, 0, sizeof(match));
418  match.ia.sin_family = AF_INET;
419  match.ia.sin_addr.s_addr = htonl(INADDR_ANY);
420  match.ia.sin_port = htons(ca_beacon_port);
421 
423  }
424 
425  /* set the port for any automatically discovered destinations. */
426  for(pNode = (osiSockAddrNode*)ellFirst(&temp);
427  pNode;
428  pNode = (osiSockAddrNode*)ellNext(&pNode->node))
429  {
430  if(pNode->addr.ia.sin_port==0)
431  pNode->addr.ia.sin_port = htons(ca_beacon_port);
432  }
433 
435  }
436 
437  if (ellCount(&beaconAddrList)==0)
438  fprintf(stderr, "Warning: RSRV has empty beacon address list\n");
439 
440  {
442  ELLLIST temp = ELLLIST_INIT,
443  temp2= ELLLIST_INIT;
444  size_t idx = 0;
445 
447  removeDuplicateAddresses(&temp2, &temp, 0);
448 
449  /* Keep the list of addresses to ignore in an array on the assumption that
450  * it is short enough that using a hash table would be slower.
451  * 0.0.0.0 indicates end of list
452  */
453  casIgnoreAddrs = callocMustSucceed(1+ellCount(&temp2), sizeof(casIgnoreAddrs[0]), "casIgnoreAddrs");
454 
455  while((node=(osiSockAddrNode*)ellGet(&temp2))!=NULL)
456  {
457  casIgnoreAddrs[idx++] = node->addr.ia.sin_addr.s_addr;
458  free(node);
459  }
460  casIgnoreAddrs[idx] = 0;
461  }
462 }
463 
464 /*
465  * rsrv_init ()
466  */
467 static
468 void rsrv_init (void)
469 {
470  long maxBytesAsALong;
471  long status;
472  SOCKET *socks;
473  int autoMaxBytes;
474 
476 
477  freeListInitPvt ( &rsrvClientFreeList, sizeof(struct client), 8 );
478  freeListInitPvt ( &rsrvChanFreeList, sizeof(struct channel_in_use), 512 );
479  freeListInitPvt ( &rsrvEventFreeList, sizeof(struct event_ext), 512 );
482 
484 
485  rsrvCurrentClient = epicsThreadPrivateCreate ();
486 
489  (unsigned short) CA_SERVER_PORT );
490  }
491  else {
493  (unsigned short) CA_SERVER_PORT );
494  }
496 
499  (unsigned short) CA_REPEATER_PORT );
500  }
501  else {
503  (unsigned short) CA_REPEATER_PORT );
504  }
505 
506  status = envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong );
507  if ( status || maxBytesAsALong < 0 ) {
508  errlogPrintf ( "CAS: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" );
510  }
511  else {
512  /* allow room for the protocol header so that they get the array size they requested */
513  static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t );
514  ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong;
515  if ( maxBytes < 0xffffffff - headerSize ) {
516  maxBytes += headerSize;
517  }
518  else {
519  maxBytes = 0xffffffff;
520  }
521  if ( maxBytes < MAX_TCP ) {
522  errlogPrintf ( "CAS: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP );
524  }
525  else {
526  rsrvSizeofLargeBufTCP = maxBytes;
527  }
528  }
529 
531  autoMaxBytes = 1;
532 
533  if (!autoMaxBytes)
535  else
538  if (!pCaBucket)
539  cantProceed("RSRV failed to allocate ID lookup table\n");
540 
541  rsrv_build_addr_lists();
542 
547 
548  /* Thread priorites
549  * Now starting per interface
550  * TCP Listener: epicsThreadPriorityCAServerLow-2
551  * Name receiver: epicsThreadPriorityCAServerLow-4
552  * Now starting global
553  * Beacon sender: epicsThreadPriorityCAServerLow-3
554  * Started later per TCP client
555  * TCP receiver: epicsThreadPriorityCAServerLow
556  * TCP sender : epicsThreadPriorityCAServerLow-1
557  */
558  {
559  unsigned i;
561 
562  for(i=1; i<NELEMENTS(threadPrios); i++)
563  {
565  threadPrios[i-1], &threadPrios[i]))
566  {
567  /* on failure use the lowest known */
568  threadPrios[i] = threadPrios[i-1];
569  }
570  }
571  }
572 
573  {
574  unsigned short sport = ca_server_port;
575  socks = rsrv_grab_tcp(&sport);
576 
577  if ( sport != ca_server_port ) {
578  ca_server_port = sport;
579  errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
580  errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
581  ca_server_port );
582  errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
583  errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
584  errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
585  }
586  }
587 
588  /* start servers (TCP and UDP(s) for each interface.
589  */
590  {
591  int havesometcp = 0;
592  ELLNODE *cur;
593  int i;
594 
595  for (i=0, cur=ellFirst(&casIntfAddrList); cur; i++, cur=ellNext(cur))
596  {
597  char ifaceName[40];
598  rsrv_iface_config *conf;
599 
600  conf = callocMustSucceed(1, sizeof(*conf), "rsrv_init");
601 
602  conf->tcpAddr = ((osiSockAddrNode *)cur)->addr;
603  conf->tcpAddr.ia.sin_port = htons(ca_server_port);
604  conf->tcp = socks[i];
605  socks[i] = INVALID_SOCKET;
606 
607  ipAddrToDottedIP (&conf->tcpAddr.ia, ifaceName, sizeof(ifaceName));
608 
609  conf->udp = conf->udpbcast = INVALID_SOCKET;
610 
611  /* create and bind UDP name receiver socket(s) */
612 
613  conf->udp = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
614  if(conf->udp==INVALID_SOCKET)
615  cantProceed("rsrv_init ran out of udp sockets");
616 
617  conf->udpAddr = conf->tcpAddr;
618  conf->udpAddr.ia.sin_port = htons(ca_udp_port);
619 
621 
622  if(tryBind(conf->udp, &conf->udpAddr, "UDP unicast socket"))
623  goto cleanup;
624 
625 #ifdef IP_ADD_MEMBERSHIP
626  /* join UDP socket to any multicast groups */
627  {
628  osiSockAddrNode *pNode;
629 
630  for(pNode = (osiSockAddrNode*)ellFirst(&casMCastAddrList);
631  pNode;
632  pNode = (osiSockAddrNode*)ellNext(&pNode->node))
633  {
634  struct ip_mreq mreq;
635 
636  memset(&mreq, 0, sizeof(mreq));
637  mreq.imr_multiaddr = pNode->addr.ia.sin_addr;
638  mreq.imr_interface.s_addr = conf->udpAddr.ia.sin_addr.s_addr;
639 
640  if (setsockopt(conf->udp, IPPROTO_IP, IP_ADD_MEMBERSHIP,
641  (char *) &mreq, sizeof(mreq))!=0) {
642  struct sockaddr_in temp;
643  char name[40];
644  char sockErrBuf[64];
645  temp.sin_family = AF_INET;
646  temp.sin_addr = mreq.imr_multiaddr;
647  temp.sin_port = conf->udpAddr.ia.sin_port;
649  sockErrBuf, sizeof ( sockErrBuf ) );
650  ipAddrToDottedIP (&temp, name, sizeof(name));
651  errlogPrintf("CAS: Socket mcast join %s to %s failed: %s\n",
652  ifaceName, name, sockErrBuf );
653  }
654  }
655  }
656 #else
658  fprintf(stderr, "IPv4 Multicast name lookup not supported by this target\n");
659  }
660 #endif
661 
662 #if !(defined(_WIN32) || defined(__CYGWIN__))
663  /* An oddness of BSD sockets (not winsock) is that binding to
664  * INADDR_ANY will receive unicast and broadcast, but binding to
665  * a specific interface address receives only unicast. The trick
666  * is to bind a second socket to the interface broadcast address,
667  * which will then receive only broadcasts.
668  */
669  if(conf->udpAddr.ia.sin_addr.s_addr!=htonl(INADDR_ANY)) {
670  /* find interface broadcast address */
671  ELLLIST bcastList = ELLLIST_INIT;
672  osiSockAddrNode *pNode;
673 
675  conf->udp, &conf->udpAddr); // match addr
676 
677  if(ellCount(&bcastList)==0) {
678  fprintf(stderr, "Warning: Can't find broadcast address of interface %s\n"
679  " Name lookup may not work on this interface\n", ifaceName);
680  } else {
681  if(ellCount(&bcastList)>1 && conf->udpAddr.ia.sin_addr.s_addr!=htonl(INADDR_ANY))
682  printf("Interface %s has more than one broadcast address?\n", ifaceName);
683 
684  pNode = (osiSockAddrNode*)ellFirst(&bcastList);
685 
686  conf->udpbcast = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0);
687  if(conf->udpbcast==INVALID_SOCKET)
688  cantProceed("rsrv_init ran out of udp sockets for bcast");
689 
691 
692  conf->udpbcastAddr = conf->udpAddr;
693  conf->udpbcastAddr.ia.sin_addr.s_addr = pNode->addr.ia.sin_addr.s_addr;
694 
695  if(tryBind(conf->udpbcast, &conf->udpbcastAddr, "UDP Socket bcast"))
696  goto cleanup;
697  }
698 
699  ellFree(&bcastList);
700  }
701 
702 #endif /* !(defined(_WIN32) || defined(__CYGWIN__)) */
703 
704  ellAdd(&servers, &conf->node);
705 
706  /* have all sockets, time to start some threads */
707 
708  epicsThreadMustCreate("CAS-TCP", threadPrios[2],
710  &req_server, conf);
711 
713 
714  epicsThreadMustCreate("CAS-UDP", threadPrios[4],
716  &cast_server, conf);
717 
719 
720 #if !(defined(_WIN32) || defined(__CYGWIN__))
721  if(conf->udpbcast != INVALID_SOCKET) {
722  conf->startbcast = 1;
723 
724  epicsThreadMustCreate("CAS-UDP2", threadPrios[4],
726  &cast_server, conf);
727 
729 
730  conf->startbcast = 0;
731  }
732 #endif /* !(defined(_WIN32) || defined(__CYGWIN__)) */
733 
734  havesometcp = 1;
735  continue;
736  cleanup:
737  epicsSocketDestroy(conf->tcp);
738  if(conf->udp!=INVALID_SOCKET) epicsSocketDestroy(conf->udp);
740  free(conf);
741  }
742 
743  if(!havesometcp)
744  cantProceed("CAS: No TCP server started\n");
745  }
746 
747  /* servers list is considered read-only from this point */
748 
749  epicsThreadMustCreate("CAS-beacon", threadPrios[3],
752 
754 }
755 
756 static
757 void rsrv_run (void)
758 {
759  castcp_ctl = ctlRun;
760  casudp_ctl = ctlRun;
761  beacon_ctl = ctlRun;
762 }
763 
764 static
765 void rsrv_pause (void)
766 {
770 }
771 
772 static unsigned countChanListBytes (
773  struct client *client, ELLLIST * pList )
774 {
775  struct channel_in_use * pciu;
776  unsigned bytes_reserved = 0;
777 
778  epicsMutexMustLock ( client->chanListLock );
779  pciu = ( struct channel_in_use * ) pList->node.next;
780  while ( pciu ) {
781  bytes_reserved += sizeof(struct channel_in_use);
782  bytes_reserved += sizeof(struct event_ext)*ellCount( &pciu->eventq );
783  bytes_reserved += rsrvSizeOfPutNotify ( pciu->pPutNotify );
784  pciu = ( struct channel_in_use * ) ellNext( &pciu->node );
785  }
786  epicsMutexUnlock ( client->chanListLock );
787 
788  return bytes_reserved;
789 }
790 
791 static void showChanList (
792  struct client * client, unsigned level, ELLLIST * pList )
793 {
794  struct channel_in_use * pciu;
795  epicsMutexMustLock ( client->chanListLock );
796  pciu = (struct channel_in_use *) pList->node.next;
797  while ( pciu ){
798  dbChannelShow ( pciu->dbch, level, 8 );
799  if ( level >= 1u )
800  printf( "%12s# on eventq=%d, access=%c%c\n", "",
801  ellCount ( &pciu->eventq ),
802  asCheckGet ( pciu->asClientPVT ) ? 'r': '-',
803  rsrvCheckPut ( pciu ) ? 'w': '-' );
804  pciu = ( struct channel_in_use * ) ellNext ( &pciu->node );
805  }
806  epicsMutexUnlock ( client->chanListLock );
807 }
808 
809 /*
810  * log_one_client ()
811  */
812 static void log_one_client (struct client *client, unsigned level)
813 {
814  char clientIP[40];
815  int n;
816 
817  ipAddrToDottedIP (&client->addr, clientIP, sizeof(clientIP));
818 
819  if ( client->proto == IPPROTO_UDP ) {
820  printf ( "\tLast name requested by %s:\n",
821  clientIP );
822  }
823  else if ( client->proto == IPPROTO_TCP ) {
824  printf ( " TCP client at %s '%s':\n",
825  clientIP,
826  client->pHostName ? client->pHostName : "" );
827  }
828  else {
829  printf ( " Unknown client at %s '%s':\n",
830  clientIP,
831  client->pHostName ? client->pHostName : "" );
832  }
833 
834  n = ellCount(&client->chanList) + ellCount(&client->chanPendingUpdateARList);
835  printf ( "\tUser '%s', V%u.%u, Priority = %u, %d Channel%s\n",
836  client->pUserName ? client->pUserName : "",
838  client->minor_version_number,
839  client->priority,
840  n, n == 1 ? "" : "s" );
841 
842  if ( level >= 3u ) {
843  double send_delay;
844  double recv_delay;
845  char *state[] = {"up", "down"};
846  epicsTimeStamp current;
847 
848  epicsTimeGetCurrent(&current);
849  send_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_send);
850  recv_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_recv);
851 
852  printf ("\tTask Id = %p, Socket FD = %d\n",
853  (void *) client->tid, (int)client->sock);
854  printf(
855  "\t%.2f secs since last send, %.2f secs since last receive\n",
856  send_delay, recv_delay);
857  printf(
858  "\tUnprocessed request bytes = %u, Undelivered response bytes = %u\n",
859  client->recv.cnt - client->recv.stk,
860  client->send.stk );
861  printf(
862  "\tState = %s%s%s\n",
863  state[client->disconnect?1:0],
864  client->send.type == mbtLargeTCP ? " jumbo-send-buf" : "",
865  client->recv.type == mbtLargeTCP ? " jumbo-recv-buf" : "");
866  }
867 
868  if ( level >= 1u ) {
869  showChanList ( client, level - 1u, & client->chanList );
870  showChanList ( client, level - 1u, & client->chanPendingUpdateARList );
871  }
872 
873  if ( level >= 4u ) {
874  unsigned bytes_reserved = sizeof(struct client);
875 
876  bytes_reserved += countChanListBytes (
877  client, & client->chanList );
878  bytes_reserved += countChanListBytes (
879  client, & client->chanPendingUpdateARList );
880  printf( "\t%d bytes allocated\n", bytes_reserved);
881  printf( "\tSend Lock:\n\t ");
882  epicsMutexShow(client->lock,1);
883  printf( "\tPut Notify Lock:\n\t ");
884  epicsMutexShow (client->putNotifyLock,1);
885  printf( "\tAddress Queue Lock:\n\t ");
886  epicsMutexShow (client->chanListLock,1);
887  printf( "\tEvent Queue Lock:\n\t ");
888  epicsMutexShow (client->eventqLock,1);
889  printf( "\tBlock Semaphore:\n\t ");
890  epicsEventShow (client->blockSem,1);
891  }
892 }
893 
894 /*
895  * casr()
896  */
897 void casr (unsigned level)
898 {
899  size_t bytes_reserved;
900  int n;
901 
902  if ( ! clientQlock ) {
903  return;
904  }
905 
906  printf ("Channel Access Server V%s\n",
908 
910  n = ellCount ( &clientQ );
911  if (n == 0) {
912  printf("No clients connected.\n");
913  }
914  else if (level == 0) {
915  printf("%d client%s connected.\n",
916  n, n == 1 ? "" : "s" );
917  }
918  else {
919  struct client *client = (struct client *) ellFirst ( &clientQ );
920 
921  printf("%d client%s connected:\n",
922  n, n == 1 ? "" : "s" );
923  while (client) {
924  log_one_client(client, level - 1);
925  client = (struct client *) ellNext(&client->node);
926  }
927  }
929 
930  if (level>=1) {
932  while (iface) {
933  char buf[40];
934 
935  ipAddrToDottedIP (&iface->tcpAddr.ia, buf, sizeof(buf));
936  printf("CAS-TCP server on %s with\n", buf);
937 
938  ipAddrToDottedIP (&iface->udpAddr.ia, buf, sizeof(buf));
939 #if defined(_WIN32)
940  printf(" CAS-UDP name server on %s\n", buf);
941  if (level >= 2)
942  log_one_client(iface->client, level - 2);
943 #else
944  if (iface->udpbcast==INVALID_SOCKET) {
945  printf(" CAS-UDP name server on %s\n", buf);
946  if (level >= 2)
947  log_one_client(iface->client, level - 2);
948  }
949  else {
950  printf(" CAS-UDP unicast name server on %s\n", buf);
951  if (level >= 2)
952  log_one_client(iface->client, level - 2);
953  ipAddrToDottedIP (&iface->udpbcastAddr.ia, buf, sizeof(buf));
954  printf(" CAS-UDP broadcast name server on %s\n", buf);
955  if (level >= 2)
956  log_one_client(iface->bclient, level - 2);
957  }
958 #endif
959 
960  iface = (rsrv_iface_config *) ellNext(&iface->node);
961  }
962  }
963 
964  if (level>=1) {
965  osiSockAddrNode * pAddr;
966  char buf[40];
967  int n = ellCount(&casMCastAddrList);
968 
969  if (n) {
970  printf("Monitoring %d multicast address%s:\n",
971  n, n == 1 ? "" : "es");
972  for(pAddr = (osiSockAddrNode*)ellFirst(&casMCastAddrList);
973  pAddr;
974  pAddr = (osiSockAddrNode*)ellNext(&pAddr->node))
975  {
976  ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf));
977  printf(" %s\n", buf);
978  }
979  }
980 
981  n = ellCount(&beaconAddrList);
982  printf("Sending CAS-beacons to %d address%s:\n",
983  n, n == 1 ? "" : "es");
984  for(pAddr = (osiSockAddrNode*)ellFirst(&beaconAddrList);
985  pAddr;
986  pAddr = (osiSockAddrNode*)ellNext(&pAddr->node))
987  {
988  ipAddrToDottedIP (&pAddr->addr.ia, buf, sizeof(buf));
989  printf(" %s\n", buf);
990  }
991 
992  if (casIgnoreAddrs[0]) { /* 0 indicates end of array */
993  size_t i;
994  printf("Ignoring UDP messages from address%s\n",
995  n == 1 ? "" : "es");
996  for(i=0; casIgnoreAddrs[i]; i++)
997  {
998  struct sockaddr_in addr;
999  memset(&addr, 0, sizeof(addr));
1000  addr.sin_family = AF_INET;
1001  addr.sin_addr.s_addr = casIgnoreAddrs[i];
1002  addr.sin_port = 0;
1003  ipAddrToDottedIP(&addr, buf, sizeof(buf));
1004  printf(" %s\n", buf);
1005  }
1006  }
1007  }
1008 
1009  if (level>=4u) {
1010  bytes_reserved = 0u;
1011  bytes_reserved += sizeof (struct client) *
1013  bytes_reserved += sizeof (struct channel_in_use) *
1015  bytes_reserved += sizeof(struct event_ext) *
1017  bytes_reserved += MAX_TCP *
1020  bytes_reserved += rsrvSizeofLargeBufTCP *
1022  }
1023  bytes_reserved += rsrvSizeOfPutNotify ( 0 ) *
1025  printf( "Free-lists total %u bytes, comprising\n",
1026  (unsigned int) bytes_reserved);
1027  printf( " %u client(s), %u channel(s), %u monitor event(s), %u putNotify(s)\n",
1028  (unsigned int) freeListItemsAvail ( rsrvClientFreeList ),
1029  (unsigned int) freeListItemsAvail ( rsrvChanFreeList ),
1030  (unsigned int) freeListItemsAvail ( rsrvEventFreeList ),
1031  (unsigned int) freeListItemsAvail ( rsrvPutNotifyFreeList ));
1032  printf( " %u small (%u byte) buffers, %u jumbo (%u byte) buffers\n",
1033  (unsigned int) freeListItemsAvail ( rsrvSmallBufFreeListTCP ),
1034  MAX_TCP,
1035  (unsigned int)(rsrvLargeBufFreeListTCP ? freeListItemsAvail ( rsrvLargeBufFreeListTCP ) : -1),
1037  printf( "Server resource id table:\n");
1038  LOCK_CLIENTQ;
1041  }
1042 }
1043 
1044 /*
1045  * destroy_client ()
1046  */
1047 void destroy_client ( struct client *client )
1048 {
1049  if ( ! client ) {
1050  return;
1051  }
1052 
1053  if ( client->tid != 0 ) {
1054  taskwdRemove ( client->tid );
1055  }
1056 
1057  if ( client->sock != INVALID_SOCKET ) {
1058  epicsSocketDestroy ( client->sock );
1059  }
1060 
1061  if ( client->proto == IPPROTO_TCP ) {
1062  if ( client->send.buf ) {
1063  if ( client->send.type == mbtSmallTCP ) {
1065  }
1066  else if ( client->send.type == mbtLargeTCP ) {
1069  else
1070  free(client->send.buf);
1071  }
1072  else {
1073  errlogPrintf ( "CAS: Corrupt send buffer free list type code=%u during client cleanup?\n",
1074  client->send.type );
1075  }
1076  }
1077  if ( client->recv.buf ) {
1078  if ( client->recv.type == mbtSmallTCP ) {
1080  }
1081  else if ( client->recv.type == mbtLargeTCP ) {
1084  else
1085  free(client->recv.buf);
1086  }
1087  else {
1088  errlogPrintf ( "CAS: Corrupt recv buffer free list type code=%u during client cleanup?\n",
1089  client->send.type );
1090  }
1091  }
1092  }
1093  else if ( client->proto == IPPROTO_UDP ) {
1094  if ( client->send.buf ) {
1095  free ( client->send.buf );
1096  }
1097  if ( client->recv.buf ) {
1098  free ( client->recv.buf );
1099  }
1100  }
1101 
1102  if ( client->eventqLock ) {
1103  epicsMutexDestroy ( client->eventqLock );
1104  }
1105 
1106  if ( client->chanListLock ) {
1107  epicsMutexDestroy ( client->chanListLock );
1108  }
1109 
1110  if ( client->putNotifyLock ) {
1111  epicsMutexDestroy ( client->putNotifyLock );
1112  }
1113 
1114  if ( client->lock ) {
1115  epicsMutexDestroy ( client->lock );
1116  }
1117 
1118  if ( client->blockSem ) {
1119  epicsEventDestroy ( client->blockSem );
1120  }
1121 
1122  if ( client->pUserName ) {
1123  free ( client->pUserName );
1124  }
1125 
1126  if ( client->pHostName ) {
1127  free ( client->pHostName );
1128  }
1129 
1130  freeListFree ( rsrvClientFreeList, client );
1131 }
1132 
1133 static void destroyAllChannels (
1134  struct client * client, ELLLIST * pList )
1135 {
1136  if ( !client->chanListLock || !client->eventqLock ) {
1137  return;
1138  }
1139 
1140  while ( TRUE ) {
1141  struct event_ext *pevext;
1142  int status;
1143  struct channel_in_use *pciu;
1144 
1145  epicsMutexMustLock ( client->chanListLock );
1146  pciu = (struct channel_in_use *) ellGet ( pList );
1147  if(pciu) pciu->state = rsrvCS_shutdown;
1148  epicsMutexUnlock ( client->chanListLock );
1149 
1150  if ( ! pciu ) {
1151  break;
1152  }
1153 
1154  while ( TRUE ) {
1155  /*
1156  * AS state change could be using this list
1157  */
1158  epicsMutexMustLock ( client->eventqLock );
1159  pevext = (struct event_ext *) ellGet ( &pciu->eventq );
1160  epicsMutexUnlock ( client->eventqLock );
1161 
1162  if ( ! pevext ) {
1163  break;
1164  }
1165 
1166  if ( pevext->pdbev ) {
1167  db_cancel_event (pevext->pdbev);
1168  }
1169  freeListFree (rsrvEventFreeList, pevext);
1170  }
1171  rsrvFreePutNotify ( client, pciu->pPutNotify );
1172  LOCK_CLIENTQ;
1173  status = bucketRemoveItemUnsignedId ( pCaBucket, &pciu->sid);
1174  rsrvChannelCount--;
1176  if ( status != S_bucket_success ) {
1177  errPrintf ( status, __FILE__, __LINE__,
1178  "Bad id=%d at close", pciu->sid);
1179  }
1180  status = asRemoveClient(&pciu->asClientPVT);
1181  if ( status && status != S_asLib_asNotActive ) {
1182  printf ( "bad asRemoveClient() status was %x \n", status );
1183  errPrintf ( status, __FILE__, __LINE__, "asRemoveClient" );
1184  }
1185 
1186  dbChannelDelete(pciu->dbch);
1187  freeListFree ( rsrvChanFreeList, pciu );
1188  }
1189 }
1190 
1191 void destroy_tcp_client ( struct client *client )
1192 {
1193  int status;
1194 
1195  if ( CASDEBUG > 0 ) {
1196  errlogPrintf ( "CAS: Connection %d Terminated\n", (int)client->sock );
1197  }
1198 
1199  if ( client->evuser ) {
1200  /*
1201  * turn off extra labor callbacks from the event thread
1202  */
1203  status = db_add_extra_labor_event ( client->evuser, NULL, NULL );
1204  assert ( ! status );
1205 
1206  /*
1207  * wait for extra labor in progress to comple
1208  */
1209  db_flush_extra_labor_event ( client->evuser );
1210  }
1211 
1212  destroyAllChannels ( client, & client->chanList );
1213  destroyAllChannels ( client, & client->chanPendingUpdateARList );
1214 
1215  if ( client->evuser ) {
1216  db_close_events (client->evuser);
1217  }
1218 
1219  destroy_client ( client );
1220 }
1221 
1222 /*
1223  * create_client ()
1224  */
1225 struct client * create_client ( SOCKET sock, int proto )
1226 {
1227  struct client *client;
1228  int spaceAvailOnFreeList;
1229  size_t spaceNeeded;
1230 
1231  /*
1232  * stop further use of server if memory becomes scarse
1233  */
1234  spaceAvailOnFreeList = freeListItemsAvail ( rsrvClientFreeList ) > 0
1236  spaceNeeded = sizeof (struct client) + MAX_TCP;
1237  if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
1238  epicsSocketDestroy ( sock );
1239  epicsPrintf ("CAS: no space in pool for a new client (below max block thresh)\n");
1240  return NULL;
1241  }
1242 
1243  client = freeListCalloc ( rsrvClientFreeList );
1244  if ( ! client ) {
1245  epicsSocketDestroy ( sock );
1246  epicsPrintf ("CAS: no space in pool for a new client (alloc failed)\n");
1247  return NULL;
1248  }
1249 
1250  client->sock = sock;
1251  client->proto = proto;
1252 
1254  client->lock = epicsMutexCreate();
1255  client->putNotifyLock = epicsMutexCreate();
1256  client->chanListLock = epicsMutexCreate();
1257  client->eventqLock = epicsMutexCreate();
1258  if ( ! client->blockSem || ! client->lock || ! client->putNotifyLock ||
1259  ! client->chanListLock || ! client->eventqLock ) {
1260  destroy_client ( client );
1261  return NULL;
1262  }
1263 
1264  client->pUserName = NULL;
1265  client->pHostName = NULL;
1266  ellInit ( & client->chanList );
1267  ellInit ( & client->chanPendingUpdateARList );
1268  ellInit ( & client->putNotifyQue );
1269  memset ( (char *)&client->addr, 0, sizeof (client->addr) );
1270  client->tid = 0;
1271 
1272  if ( proto == IPPROTO_TCP ) {
1273  client->send.buf = (char *) freeListCalloc ( rsrvSmallBufFreeListTCP );
1274  client->send.maxstk = MAX_TCP;
1275  client->send.type = mbtSmallTCP;
1276  client->recv.buf = (char *) freeListCalloc ( rsrvSmallBufFreeListTCP );
1277  client->recv.maxstk = MAX_TCP;
1278  client->recv.type = mbtSmallTCP;
1279  }
1280  else if ( proto == IPPROTO_UDP ) {
1281  client->send.buf = malloc ( MAX_UDP_SEND );
1282  client->send.maxstk = MAX_UDP_SEND;
1283  client->send.type = mbtUDP;
1284  client->recv.buf = malloc ( MAX_UDP_RECV );
1285  client->recv.maxstk = MAX_UDP_RECV;
1286  client->recv.type = mbtUDP;
1287  }
1288  if ( ! client->send.buf || ! client->recv.buf ) {
1289  destroy_client ( client );
1290  return NULL;
1291  }
1292  client->send.stk = 0u;
1293  client->send.cnt = 0u;
1294  client->recv.stk = 0u;
1295  client->recv.cnt = 0u;
1296  client->evuser = NULL;
1297  client->priority = CA_PROTO_PRIORITY_MIN;
1298  client->disconnect = FALSE;
1302  client->recvBytesToDrain = 0u;
1303 
1304  return client;
1305 }
1306 
1307 void casAttachThreadToClient ( struct client *pClient )
1308 {
1311  pClient->tid = epicsThreadGetIdSelf ();
1312  epicsThreadPrivateSet ( rsrvCurrentClient, pClient );
1313  taskwdInsert ( pClient->tid, NULL, NULL );
1314 }
1315 
1316 static
1317 void casExpandBuffer ( struct message_buffer *buf, ca_uint32_t size, int sendbuf )
1318 {
1319  char *newbuf = NULL;
1320  unsigned newsize;
1321  enum messageBufferType newtype;
1322 
1323  assert (size > MAX_TCP);
1324 
1325  if ( size <= buf->maxstk || buf->type == mbtUDP ) return;
1326 
1327  /* try to alloc new buffer */
1328  if (size <= MAX_TCP) {
1329  return; /* shouldn't happen */
1330 
1331  } else if(!rsrvLargeBufFreeListTCP) {
1332  // round up to multiple of 4K
1333  size = ((size-1)|0xfff)+1;
1334 
1335  if (buf->type==mbtLargeTCP) {
1336  newbuf = realloc (buf->buf, size);
1337  if(newbuf)
1338  buf->buf = newbuf;
1339  } else {
1340  newbuf = malloc (size);
1341  }
1342  newtype = mbtLargeTCP;
1343  newsize = size;
1344 
1345  } else if (size <= rsrvSizeofLargeBufTCP) {
1347  newsize = rsrvSizeofLargeBufTCP;
1348  newtype = mbtLargeTCP;
1349  }
1350 
1351  if (newbuf) {
1352  /* copy existing buffer */
1353  if (sendbuf) {
1354  /* send buffer uses [0, stk) */
1355  if (!rsrvLargeBufFreeListTCP && buf->type==mbtLargeTCP) {
1356  /* realloc already copied */
1357  } else {
1358  memcpy ( newbuf, buf->buf, buf->stk );
1359  }
1360  } else {
1361  /* recv buffer uses [stk, cnt) */
1362  unsigned used;
1363  assert ( buf->cnt >= buf->stk );
1364  used = buf->cnt - buf->stk;
1365 
1366  /* buf->buf may be the same as newbuf if realloc() used */
1367  memmove ( newbuf, &buf->buf[buf->stk], used );
1368 
1369  buf->cnt = used;
1370  buf->stk = 0;
1371 
1372  }
1373 
1374  /* free existing buffer */
1375  if(buf->type==mbtSmallTCP) {
1377  } else if(rsrvLargeBufFreeListTCP && buf->type==mbtLargeTCP) {
1379  } else {
1380  /* realloc() already free()'d if necessary */
1381  }
1382 
1383  buf->buf = newbuf;
1384  buf->type = newtype;
1385  buf->maxstk = newsize;
1386  }
1387 }
1388 
1389 void casExpandSendBuffer ( struct client *pClient, ca_uint32_t size )
1390 {
1391  casExpandBuffer (&pClient->send, size, 1);
1392 }
1393 
1394 void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size )
1395 {
1396  casExpandBuffer (&pClient->recv, size, 0);
1397 }
1398 
1399 /*
1400  * create_tcp_client ()
1401  */
1402 struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr)
1403 {
1404  int status;
1405  struct client *client;
1406  int intTrue = TRUE;
1407  unsigned priorityOfEvents;
1408 
1409  /* socket passed in is destroyed here if unsuccessful */
1410  client = create_client ( sock, IPPROTO_TCP );
1411  if ( ! client ) {
1412  return NULL;
1413  }
1414 
1415  client->addr = peerAddr->ia;
1416  if(asCheckClientIP) {
1417  epicsUInt32 ip = ntohl(client->addr.sin_addr.s_addr);
1418  client->pHostName = malloc(24);
1419  if(!client->pHostName) {
1420  destroy_client ( client );
1421  return NULL;
1422  }
1423  epicsSnprintf(client->pHostName, 24,
1424  "%u.%u.%u.%u",
1425  (ip>>24)&0xff,
1426  (ip>>16)&0xff,
1427  (ip>>8)&0xff,
1428  (ip>>0)&0xff);
1429  }
1430 
1431  /*
1432  * see TCP(4P) this seems to make unsolicited single events much
1433  * faster. I take care of queue up as load increases.
1434  */
1435  status = setsockopt ( sock, IPPROTO_TCP, TCP_NODELAY,
1436  (char *) &intTrue, sizeof (intTrue) );
1437  if (status < 0) {
1438  errlogPrintf ( "CAS: TCP_NODELAY option set failed\n" );
1439  destroy_client ( client );
1440  return NULL;
1441  }
1442 
1443  /*
1444  * turn on KEEPALIVE so if the client crashes
1445  * this task will find out and exit
1446  */
1447  status = setsockopt ( sock, SOL_SOCKET, SO_KEEPALIVE,
1448  (char *) &intTrue, sizeof (intTrue) );
1449  if ( status < 0 ) {
1450  errlogPrintf ( "CAS: SO_KEEPALIVE option set failed\n" );
1451  destroy_client ( client );
1452  return NULL;
1453  }
1454 
1455  /*
1456  * some concern that vxWorks will run out of mBuf's
1457  * if this change is made
1458  *
1459  * joh 11-10-98
1460  */
1461 #if 0
1462  /*
1463  * set TCP buffer sizes to be synergistic
1464  * with CA internal buffering
1465  */
1466  i = MAX_MSG_SIZE;
1467  status = setsockopt ( sock, SOL_SOCKET, SO_SNDBUF, (char *) &i, sizeof (i) );
1468  if (status < 0) {
1469  errlogPrintf ( "CAS: SO_SNDBUF set failed\n" );
1470  destroy_client ( client );
1471  return NULL;
1472  }
1473  i = MAX_MSG_SIZE;
1474  status = setsockopt ( sock, SOL_SOCKET, SO_RCVBUF, (char *) &i, sizeof (i) );
1475  if (status < 0) {
1476  errlogPrintf ( "CAS: SO_RCVBUF set failed\n" );
1477  destroy_client ( client );
1478  return NULL;
1479  }
1480 #endif
1481 
1482  client->evuser = (struct event_user *) db_init_events ();
1483  if ( ! client->evuser ) {
1484  errlogPrintf ("CAS: unable to init the event facility\n");
1485  destroy_tcp_client (client);
1486  return NULL;
1487  }
1488 
1489  status = db_add_extra_labor_event ( client->evuser, rsrv_extra_labor, client );
1490  if (status != DB_EVENT_OK) {
1491  errlogPrintf("CAS: unable to setup the event facility\n");
1492  destroy_tcp_client (client);
1493  return NULL;
1494  }
1495 
1496  {
1498 
1500  if ( tbs != epicsThreadBooleanStatusSuccess ) {
1501  priorityOfEvents = epicsThreadPriorityCAServerLow;
1502  }
1503  }
1504 
1505  status = db_start_events ( client->evuser, "CAS-event",
1506  NULL, NULL, priorityOfEvents );
1507  if ( status != DB_EVENT_OK ) {
1508  errlogPrintf ( "CAS: unable to start the event facility\n" );
1509  destroy_tcp_client ( client );
1510  return NULL;
1511  }
1512 
1513  /*
1514  * add first version message should it be needed
1515  */
1516  rsrv_version_reply ( client );
1517 
1518  if ( CASDEBUG > 0 ) {
1519  char buf[64];
1520  ipAddrToDottedIP ( &client->addr, buf, sizeof(buf) );
1521  errlogPrintf ( "CAS: conn req from %s\n", buf );
1522  }
1523 
1524  return client;
1525 }
1526 
1527 void casStatsFetch ( unsigned *pChanCount, unsigned *pCircuitCount )
1528 {
1529  LOCK_CLIENTQ;
1530  {
1531  int circuitCount = ellCount ( &clientQ );
1532  if ( circuitCount < 0 ) {
1533  *pCircuitCount = 0;
1534  }
1535  else {
1536  *pCircuitCount = (unsigned) circuitCount;
1537  }
1538  *pChanCount = rsrvChannelCount;
1539  }
1541 }
1542 
1543 
1544 static dbServer rsrv_server = {
1545  ELLNODE_INIT,
1546  "rsrv",
1547  casr,
1548  casStatsFetch,
1550  rsrv_init,
1551  rsrv_run,
1552  rsrv_pause
1553 };
1554 
1556 {
1557  dbRegisterServer(&rsrv_server);
1558 }
LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses(ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr)
Definition: osdNetIntf.c:68
LIBCA_API void epicsStdCall removeDuplicateAddresses(struct ELLLIST *pDestList, ELLLIST *pSrcList, int silent)
Definition: iocinf.cpp:123
#define CA_REPEATER_PORT
Definition: caProto.h:54
struct dbChannel * dbch
Definition: server.h:139
LIBCOM_API void epicsStdCall epicsSocketDestroy(SOCKET s)
Definition: osdSock.c:117
GLBLTYPE int CASDEBUG
Definition: server.h:190
LIBCOM_API void *epicsStdCall freeListCalloc(void *pvt)
Definition: freeListLib.c:60
void casAttachThreadToClient(struct client *pClient)
SOCKET udpbcast
Definition: server.h:163
epicsThreadId epicsStdCall epicsThreadMustCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
#define MAX_TCP
Definition: caProto.h:63
#define SOCK_EADDRNOTAVAIL
Definition: osdSock.h:57
void taskwdInsert(epicsThreadId tid, TASKWDFUNC callback, void *usr)
Definition: taskwd.c:176
void rsrvFreePutNotify(client *pClient, struct rsrv_put_notify *pNotify)
Definition: camessage.c:1616
struct message_buffer recv
Definition: server.h:81
#define INVALID_SOCKET
Definition: osdSock.h:32
int rsrv_version_reply(struct client *client)
Definition: camessage.c:2141
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
epicsThreadBooleanStatus
Definition: epicsThread.h:93
#define FALSE
Definition: dbDefs.h:32
LIBCOM_API int asCheckClientIP
Definition: asLibRoutines.c:31
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
osiSockAddr addr
Definition: osiSock.h:163
unsigned cnt
Definition: server.h:70
struct client client
LIBCOM_API void epicsStdCall epicsSignalInstallSigPipeIgnore(void)
Definition: osdSignal.cpp:17
void destroy_tcp_client(struct client *client)
#define SOCK_EADDRINUSE
Definition: osdSock.h:56
#define CA_MAJOR_PROTOCOL_REVISION
Definition: caProto.h:26
void epicsStdCall epicsMutexDestroy(epicsMutexId pmutexNode)
Destroy an epicsMutex semaphore.
Definition: epicsMutex.cpp:127
pvd::Status status
const unsigned sid
Definition: server.h:137
unsigned maxstk
Definition: server.h:68
char * pUserName
Definition: server.h:93
int osiSocklen_t
Definition: osdSock.h:36
GLBLTYPE unsigned int threadPrios[5]
Definition: server.h:216
#define asCheckGet(asClientPvt)
Definition: asLib.h:43
int i
Definition: scan.c:967
LIBCOM_API const char *epicsStdCall envGetConfigParamPtr(const ENV_PARAM *pParam)
Get a configuration parameter&#39;s value or default string.
Definition: envSubr.c:81
int rsrvCheckPut(const struct channel_in_use *pciu)
Definition: camessage.c:2566
struct sockaddr sa
Definition: osiSock.h:158
unsigned int startbcast
Definition: server.h:166
GLBLTYPE SOCKET beaconSocket
Definition: server.h:195
struct rsrv_put_notify * pPutNotify
Definition: server.h:135
LIBCA_API int epicsStdCall addAddrToChannelAccessAddressList(struct ELLLIST *pList, const ENV_PARAM *pEnv, unsigned short port, int ignoreNonDefaultPort)
Definition: iocinf.cpp:74
GLBLTYPE ELLLIST casMCastAddrList
Definition: server.h:196
Definition: server.h:63
LIBCOM_API int epicsStdCall bucketShow(BUCKET *pb)
Display information about a hash table.
Definition: bucketLib.c:476
struct sockaddr_in ia
Definition: osiSock.h:157
osiSockAddr tcpAddr
Definition: server.h:160
osiSockAddr udpbcastAddr
Definition: server.h:160
void rsrv_online_notify_task(void *pParm)
Definition: online_notify.c:40
void cast_server(void *pParm)
Definition: cast_server.c:116
ELLNODE node
Definition: server.h:159
void casExpandRecvBuffer(struct client *pClient, ca_uint32_t size)
epicsThreadPrivateId rsrvCurrentClient
Definition: caservertask.c:50
GLBLTYPE void * rsrvSmallBufFreeListTCP
Definition: server.h:203
#define printf
Definition: epicsStdio.h:41
GLBLTYPE epicsMutexId clientQlock
Definition: server.h:198
unsigned int ca_uint32_t
Definition: caProto.h:76
ELLNODE * ellGet(ELLLIST *pList)
Deletes and returns the first node from a list.
Definition: ellLib.c:147
LIBCOM_API const ENV_PARAM EPICS_CA_MAX_ARRAY_BYTES
#define CA_UKN_MINOR_VERSION
Definition: caProto.h:29
epicsEventId blockSem
Definition: server.h:95
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
#define NULL
Definition: catime.c:38
while(1)
Definition: scan.c:995
#define CA_SERVER_PORT
Definition: caProto.h:53
void epicsStdCall epicsSocketEnableAddressUseForDatagramFanout(SOCKET s)
Functions to check the state of the system memory pool.
LIBCOM_API void epicsStdCall freeListInitPvt(void **ppvt, int size, int nmalloc)
Definition: freeListLib.c:44
struct client * client
Definition: server.h:164
#define LOCK_CLIENTQ
Definition: server.h:223
LIBCOM_API int epicsStdCall osiSufficentSpaceInPool(size_t contiguousBlockSize)
Checks if a memory block of a specific size can be safely allocated.
Definition: osdPoolStatus.c:19
unsigned int epicsUInt32
Definition: epicsTypes.h:43
#define ELLLIST_INIT
Value of an empty list.
Definition: ellLib.h:63
void casr(unsigned level)
Definition: caservertask.c:897
enum rsrvChanState state
Definition: server.h:141
void initializePutNotifyFreeList(void)
Definition: camessage.c:1530
int osiSockOptMcastLoop_t
Definition: osdSock.h:37
SOCKET sock
Definition: server.h:96
LIBCOM_API epicsEventId epicsEventMustCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code.
Definition: epicsEvent.cpp:106
unsigned stk
Definition: server.h:67
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
osiSockAddr udpAddr
Definition: server.h:160
#define CA_VERSION_STRING(MINOR_REVISION)
Definition: caProto.h:27
int proto
Definition: server.h:97
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
LIBCOM_API void epicsEventMustWait(epicsEventId id)
Wait for an event (see epicsEventWait()).
Definition: epicsEvent.cpp:123
ELLLIST putNotifyQue
Definition: server.h:88
struct sockaddr_in addr
Definition: server.h:89
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
#define CA_MINOR_PROTOCOL_REVISION
Definition: nciu.h:35
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
void destroy_client(struct client *client)
#define SOCK_EACCES
Definition: osdSock.h:55
GLBLTYPE ELLLIST casIntfAddrList
Definition: server.h:196
char * pHostName
Definition: server.h:94
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
GLBLTYPE ELLLIST beaconAddrList
Definition: server.h:194
LIBCOM_API SOCKET epicsStdCall epicsSocketCreate(int domain, int type, int protocol)
Definition: osdSock.c:71
LIBCOM_API const ENV_PARAM EPICS_CAS_SERVER_PORT
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
#define ellFree(PLIST)
Free up the list.
Definition: ellLib.h:108
LIBCOM_API const ENV_PARAM EPICS_CA_SERVER_PORT
LIBCOM_API const ENV_PARAM EPICS_CAS_INTF_ADDR_LIST
GLBLTYPE void * rsrvClientFreeList
Definition: server.h:200
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Definition: osdThread.c:664
epicsMutexId chanListLock
Definition: server.h:84
void errPrintf(long status, const char *pFileName, int lineno, const char *pformat,...)
Definition: errlog.c:383
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
char disconnect
Definition: server.h:103
LIBCOM_API long epicsStdCall envGetBoolConfigParam(const ENV_PARAM *pParam, int *pBool)
Get value of a boolean configuration parameter.
Definition: envSubr.c:325
LIBCOM_API const ENV_PARAM EPICS_CAS_AUTO_BEACON_ADDR_LIST
epicsThreadId tid
Definition: server.h:98
Definition: server.h:169
Definition: server.h:76
struct message_buffer send
Definition: server.h:79
epicsTimeStamp time_at_last_recv
Definition: server.h:91
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API const ENV_PARAM EPICS_CA_REPEATER_PORT
unsigned recvBytesToDrain
Definition: server.h:101
LIBCOM_API void epicsStdCall epicsSocketEnableAddressReuseDuringTimeWaitState(SOCKET s)
LIBCOM_API void epicsStdCall freeListFree(void *pvt, void *pmem)
Definition: freeListLib.c:131
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId, void *)
Definition: osdThread.c:961
int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
Get current time into *pDest.
LIBCOM_API int epicsStdCall epicsSocketAccept(int sock, struct sockaddr *pAddr, osiSocklen_t *addrlen)
Definition: osdSock.c:94
GLBLTYPE void * rsrvLargeBufFreeListTCP
Definition: server.h:204
#define CA_PROTO_PRIORITY_MIN
Definition: caProto.h:66
#define epicsPrintf
Definition: errlog.h:51
LIBCOM_API size_t epicsStdCall freeListItemsAvail(void *pvt)
Definition: freeListLib.c:171
epicsMutexId lock
Definition: server.h:82
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
char * buf
Definition: server.h:65
void rsrv_register_server(void)
LIBCOM_API int epicsStdCall bucketRemoveItemUnsignedId(BUCKET *prb, const unsigned *pId)
Remove an item identified by a string from the table.
Definition: bucketLib.c:415
int SOCKET
Definition: osdSock.h:31
ASCLIENTPVT asClientPVT
Definition: server.h:140
LIBCOM_API long epicsStdCall asRemoveClient(ASCLIENTPVT *asClientPvt)
LIBCOM_API void epicsEventDestroy(epicsEventId id)
Destroy an epicsEvent and any resources it holds.
Definition: osdEvent.c:70
void casExpandSendBuffer(struct client *pClient, ca_uint32_t size)
GLBLTYPE BUCKET * pCaBucket
Definition: server.h:199
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
Definition: cantProceed.c:22
#define NELEMENTS(A)
Definition: aToIPAddr.c:21
epicsMutexId eventqLock
Definition: server.h:85
LIBCOM_API void epicsStdCall epicsSignalInstallSigAlarmIgnore(void)
Definition: osdSignal.cpp:18
LIBCOM_API const ENV_PARAM EPICS_CAS_IGNORE_ADDR_LIST
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
List node type.
Definition: ellLib.h:45
struct client * create_client(SOCKET sock, int proto)
LIBCOM_API const ENV_PARAM EPICS_CAS_BEACON_ADDR_LIST
GLBLTYPE enum ctl castcp_ctl
Definition: server.h:214
GLBLTYPE epicsEventId casudp_startStopEvent
Definition: server.h:209
struct ca_hdr caHdr
APIs for the epicsEvent binary semaphore.
GLBLTYPE void * rsrvChanFreeList
Definition: server.h:201
GLBLTYPE unsigned short ca_beacon_port
Definition: server.h:191
GLBLTYPE unsigned rsrvSizeofLargeBufTCP
Definition: server.h:205
#define SOCKERRNO
Definition: osdSock.h:33
GLBLTYPE void * rsrvEventFreeList
Definition: server.h:202
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadHighestPriorityLevelBelow(unsigned int priority, unsigned *pPriorityJustBelow)
Definition: osdThread.c:740
#define MAX_UDP_RECV
Definition: caProto.h:61
#define epicsThreadPriorityCAServerLow
Definition: epicsThread.h:80
void casStatsFetch(unsigned *pChanCount, unsigned *pCircuitCount)
GLBLTYPE epicsEventId castcp_startStopEvent
Definition: server.h:211
void camsgtask(void *pParm)
Definition: camsgtask.c:42
struct ELLNODE * next
Pointer to next node in list.
Definition: ellLib.h:46
ELLLIST chanPendingUpdateARList
Definition: server.h:87
LIBCOM_API void * mallocMustSucceed(size_t size, const char *msg)
A malloc() that never returns NULL.
Definition: cantProceed.c:38
ELLLIST eventq
Definition: server.h:133
ELLNODE node
Definition: osiSock.h:162
void taskwdRemove(epicsThreadId tid)
Definition: taskwd.c:206
ELLNODE node
Definition: server.h:132
GLBLTYPE epicsUInt32 * casIgnoreAddrs
Definition: server.h:197
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
GLBLTYPE enum ctl beacon_ctl
Definition: server.h:213
LIBCOM_API long epicsStdCall envGetLongConfigParam(const ENV_PARAM *pParam, long *pLong)
Get value of a long configuration parameter.
Definition: envSubr.c:303
#define TRUE
Definition: dbDefs.h:27
messageBufferType
Definition: server.h:63
#define MAX_MSG_SIZE
Definition: caProto.h:64
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
LIBCOM_API BUCKET *epicsStdCall bucketCreate(unsigned nHashTableEntries)
Creates a new hash table.
Definition: bucketLib.c:218
GLBLTYPE unsigned short ca_server_port
Definition: server.h:191
#define epicsMutexCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:168
LIBCOM_API void cantProceed(const char *msg,...)
Definition: cantProceed.c:54
GLBLTYPE epicsEventId beacon_startStopEvent
Definition: server.h:210
void epicsStdCall epicsMutexShow(epicsMutexId pmutexNode, unsigned int level)
Display information about the semaphore.
Definition: epicsMutex.cpp:191
LIBCOM_API const ENV_PARAM EPICS_CA_MCAST_TTL
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
Time difference between left and right in seconds.
Definition: epicsTime.cpp:1048
void ellConcat(ELLLIST *pDstList, ELLLIST *pAddList)
Concatenates a list to the end of another list. The list to be added is left empty. Either list (or both) can be empty at the beginning of the operation.
Definition: ellLib.c:46
Routines for code that can&#39;t continue or return after an error.
void * evuser
Definition: server.h:92
#define stderr
Definition: epicsStdio.h:32
unsigned minor_version_number
Definition: server.h:99
OS-independent routines for ignoring Posix signals.
ELLNODE node
Definition: server.h:77
#define UNLOCK_CLIENTQ
Definition: server.h:224
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
ELLLIST chanList
Definition: server.h:86
epicsMutexId putNotifyLock
Definition: server.h:83
List header type.
Definition: ellLib.h:56
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
void rsrv_extra_labor(void *pArg)
Definition: camessage.c:1497
struct event_block * pdbev
Definition: server.h:152
LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
Definition: osdThread.c:934
ELLNODE node
Pointers to the first and last nodes on list.
Definition: ellLib.h:57
epicsTimeStamp time_at_last_send
Definition: server.h:90
#define S_bucket_success
Success, must be 0.
Definition: bucketLib.h:179
GLBLTYPE unsigned rsrvChannelCount
Definition: server.h:207
LIBCOM_API const ENV_PARAM EPICS_CA_AUTO_ARRAY_BYTES
GLBLTYPE ELLLIST servers
Definition: server.h:193
#define ELLNODE_INIT
Value of a terminal node.
Definition: ellLib.h:52
unsigned priority
Definition: server.h:102
GLBLTYPE unsigned short ca_udp_port
Definition: server.h:191
LIBCOM_API epicsEventId epicsEventCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code, or return NULL.
Definition: osdEvent.c:47
struct client * create_tcp_client(SOCKET sock, const osiSockAddr *peerAddr)
int osiSockOptMcastTTL_t
Definition: osdSock.h:38
int casClientInitiatingCurrentThread(char *pBuf, size_t bufSize)
Definition: camsgtask.c:165
#define S_asLib_asNotActive
Definition: asLib.h:137
GLBLTYPE enum ctl casudp_ctl
Definition: server.h:212
unsigned rsrvSizeOfPutNotify(struct rsrv_put_notify *pNotify)
Definition: camessage.c:1604
LIBCOM_API int epicsStdCall epicsSnprintf(char *str, size_t size, const char *format,...) EPICS_PRINTF_STYLE(3
GLBLTYPE void * rsrvPutNotifyFreeList
Definition: server.h:206
#define CAS_HASH_TABLE_SIZE
Definition: server.h:218
LIBCOM_API const ENV_PARAM EPICS_CAS_BEACON_PORT
unsigned epicsStdCall ipAddrToDottedIP(const struct sockaddr_in *paddr, char *pBuf, unsigned bufSize)
Definition: osiSock.c:144
enum messageBufferType type
Definition: server.h:71
struct client * bclient
Definition: server.h:164
#define MAX_UDP_SEND
Definition: caProto.h:62
Exporting IOC objects.
LIBCOM_API void epicsEventShow(epicsEventId id, unsigned int level)
Display information about the semaphore.
Definition: osdEvent.c:150
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810