This is Unofficial EPICS BASE Doxygen Site
camessage.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven National Laboratory.
3 * Copyright (c) 2010 Helmholtz-Zentrum Berlin
4 * fuer Materialien und Energie GmbH.
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 <johill@lanl.gov>
15  *
16  * Ralph Lange <Ralph.Lange@bessy.de>
17  */
18 
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <limits.h>
25 
26 #include "epicsEvent.h"
27 #include "epicsMutex.h"
28 #include "epicsStdio.h"
29 #include "epicsString.h"
30 #include "epicsThread.h"
31 #include "epicsTime.h"
32 #include "errlog.h"
33 #include "freeList.h"
34 #include "osiPoolStatus.h"
35 #include "osiSock.h"
36 
37 #include "caerr.h"
38 #include "net_convert.h"
39 
40 #define epicsExportSharedSymbols
41 #include "asDbLib.h"
42 #include "callback.h"
43 #include "db_access.h"
44 #include "db_access_routines.h"
45 #include "dbChannel.h"
46 #include "dbCommon.h"
47 #include "dbEvent.h"
48 #include "db_field_log.h"
49 #include "dbNotify.h"
50 #include "rsrv.h"
51 #include "server.h"
52 #include "special.h"
53 
54 #define RECORD_NAME(CHAN) (dbChannelRecord(CHAN)->name)
55 
56 static EVENTFUNC read_reply;
57 
58 #define logBadId(CLIENT, MP, PPL)\
59 logBadIdWithFileAndLineno(CLIENT, MP, PPL, __FILE__, __LINE__)
60 
61 /*
62  * for tracking db put notifies
63  */
64 typedef struct rsrv_put_notify {
66  processNotify dbPutNotify;
68  /*
69  * Include a union of all scalar types
70  * including fixed length strings so
71  * that in many cases we can avoid
72  * allocating another buffer and only
73  * use an rsrv_put_notify from its
74  * free list.
75  */
76  union {
86  /* arguments for db_put_field */
87  void *pbuffer;
88  long nRequest;
89  short dbrType;
90  /* end arguments for db_put_field */
91  void * asWritePvt;
92  unsigned valueSize; /* size of block pointed to by pbuffer */
93  char busy; /* put notify in progress */
96 
97 /*
98  * casCalloc()
99  *
100  * (dont drop below some max block threshold)
101  */
102 static void *casCalloc(size_t count, size_t size)
103 {
104  if ( UINT_MAX / size >= count ) {
105  if (!osiSufficentSpaceInPool(size*count)) {
106  return NULL;
107  }
108  return calloc(count, size);
109  }
110  else {
111  return NULL;
112  }
113 }
114 
115 /*
116  * MPTOPCIU()
117  *
118  * used to be a macro
119  */
120 static struct channel_in_use *MPTOPCIU (const caHdrLargeArray *mp)
121 {
122  struct channel_in_use *pciu;
123  const unsigned id = mp->m_cid;
124 
125  LOCK_CLIENTQ;
128 
129  return pciu;
130 }
131 
132 /* vsend_err()
133  *
134  * reflect error msg back to the client
135  *
136  * send buffer lock must be on while in this routine
137  *
138  */
139 static void vsend_err(
140 const caHdrLargeArray *curp,
141 int status,
142 struct client *client,
143 const char *pformat,
144 va_list args
145 )
146 {
147  static const ca_uint32_t maxDiagLen = 512;
148  struct channel_in_use *pciu;
149  caHdr *pReqOut;
150  char *pMsgString;
151  ca_uint32_t size;
153  int localStatus;
154 
155  switch ( curp->m_cmmd ) {
156  case CA_PROTO_EVENT_ADD:
158  case CA_PROTO_READ:
160  case CA_PROTO_WRITE:
162  pciu = MPTOPCIU(curp);
163  if(pciu){
164  cid = pciu->cid;
165  }
166  else{
167  cid = 0xffffffff;
168  }
169  break;
170 
171  case CA_PROTO_SEARCH:
172  cid = curp->m_cid;
173  break;
174 
175  case CA_PROTO_EVENTS_ON:
176  case CA_PROTO_EVENTS_OFF:
177  case CA_PROTO_READ_SYNC:
178  case CA_PROTO_SNAPSHOT:
179  default:
180  cid = 0xffffffff;
181  break;
182  }
183 
184  /*
185  * allocate plenty of space for a sprintf() buffer
186  */
187  localStatus = cas_copy_in_header ( client,
188  CA_PROTO_ERROR, maxDiagLen, 0, 0, cid, status,
189  ( void * ) &pReqOut );
190  if ( localStatus != ECA_NORMAL ) {
191  errlogPrintf ( "caserver: Unable to deliver err msg \"%s\" to client because \"%s\"\n",
192  ca_message (status), ca_message (localStatus) );
193  errlogVprintf ( pformat, args );
194  return;
195  }
196 
197  /*
198  * copy back the request protocol
199  * (in network byte order)
200  */
201  if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
202  CA_V49( client->minor_version_number ) ) {
203  ca_uint32_t *pLW = ( ca_uint32_t * ) ( pReqOut + 1 );
204  pReqOut->m_cmmd = htons ( curp->m_cmmd );
205  pReqOut->m_postsize = htons ( 0xffff );
206  pReqOut->m_dataType = htons ( curp->m_dataType );
207  pReqOut->m_count = htons ( 0u );
208  pReqOut->m_cid = htonl ( curp->m_cid );
209  pReqOut->m_available = htonl ( curp->m_available );
210  pLW[0] = htonl ( curp->m_postsize );
211  pLW[1] = htonl ( curp->m_count );
212  pMsgString = ( char * ) ( pLW + 2 );
213  size = sizeof ( caHdr ) + 2 * sizeof ( *pLW );
214  }
215  else {
216  pReqOut->m_cmmd = htons (curp->m_cmmd);
217  pReqOut->m_postsize = htons ( ( (ca_uint16_t) curp->m_postsize ) );
218  pReqOut->m_dataType = htons (curp->m_dataType);
219  pReqOut->m_count = htons ( ( (ca_uint16_t) curp->m_count ) );
220  pReqOut->m_cid = htonl (curp->m_cid);
221  pReqOut->m_available = htonl (curp->m_available);
222  pMsgString = ( char * ) ( pReqOut + 1 );
223  size = sizeof ( caHdr );
224  }
225 
226  /*
227  * add their context string into the protocol
228  */
229  localStatus = epicsVsnprintf ( pMsgString, maxDiagLen - size, pformat, args );
230  if ( localStatus >= 1 ) {
231  unsigned diagLen = ( unsigned ) localStatus;
232  if ( diagLen < maxDiagLen - size ) {
233  size += (ca_uint32_t) (diagLen + 1u);
234  }
235  else {
236  errlogPrintf (
237  "caserver: vsend_err: epicsVsnprintf detected "
238  "error message truncation, pFormat = \"%s\"\n",
239  pformat );
240  size = maxDiagLen;
241  pMsgString [ maxDiagLen - 1 ] = '\0';
242  }
243  }
244  cas_commit_msg ( client, size );
245 }
246 
247 /* send_err()
248  *
249  * reflect error msg back to the client
250  *
251  * send buffer lock must be on while in this routine
252  *
253  */
254 static void send_err (
255 const caHdrLargeArray *curp,
256 int status,
257 struct client *client,
258 const char *pformat,
259  ... )
260 {
261  va_list args;
262  va_start ( args, pformat );
263  vsend_err ( curp, status, client, pformat, args );
264  va_end ( args );
265 }
266 
267 /* log_header()
268  *
269  * Debug aid - print the header part of a message.
270  *
271  */
272 static void log_header (
273  const char *pContext,
274  struct client *client,
275  const caHdrLargeArray *mp,
276  const void *pPayLoad,
277  unsigned mnum
278 )
279 {
280  struct channel_in_use *pciu;
281  char hostName[256];
282 
283  ipAddrToDottedIP (&client->addr, hostName, sizeof(hostName));
284 
285  pciu = MPTOPCIU(mp);
286 
287  if (pContext) {
288  epicsPrintf ("CAS: request from %s => %s\n",
289  hostName, pContext);
290  }
291 
292  epicsPrintf ( "CAS: Request from %s => cmmd=%d cid=0x%x type=%d count=%d postsize=%u\n",
293  hostName, mp->m_cmmd, mp->m_cid, mp->m_dataType, mp->m_count, mp->m_postsize);
294 
295  epicsPrintf ( "CAS: Request from %s => available=0x%x \tN=%u paddr=%p\n",
296  hostName, mp->m_available, mnum, (pciu ? (void *)&pciu->dbch : NULL));
297 
298  if (mp->m_cmmd==CA_PROTO_WRITE && mp->m_dataType==DBF_STRING && pPayLoad ) {
299  epicsPrintf ( "CAS: Request from %s => Wrote string \"%s\"\n",
300  hostName, (char *)pPayLoad );
301  }
302 }
303 
304 /*
305  * logBadIdWithFileAndLineno()
306  */
307 static void logBadIdWithFileAndLineno(
308 struct client *client,
309 caHdrLargeArray *mp,
310 const void *pPayload,
311 char *pFileName,
312 unsigned lineno
313 )
314 {
315  log_header ( "bad resource ID", client, mp, pPayload, 0 );
316  SEND_LOCK ( client );
317  send_err ( mp, ECA_INTERNAL, client, "Bad Resource ID at %s.%d",
318  pFileName, lineno );
319  SEND_UNLOCK ( client );
320 }
321 
322 /*
323  * bad_udp_cmd_action()
324  */
325 static int bad_udp_cmd_action ( caHdrLargeArray *mp,
326  void *pPayload, struct client *pClient )
327 {
328  if (CASDEBUG > 0)
329  log_header ("invalid (damaged?) request code from UDP",
330  pClient, mp, pPayload, 0);
331  return RSRV_ERROR;
332 }
333 
334 /*
335  * bad_tcp_cmd_action()
336  */
337 static int bad_tcp_cmd_action ( caHdrLargeArray *mp, void *pPayload,
338  struct client *client )
339 {
340  const char *pCtx = "invalid (damaged?) request code from TCP";
341  log_header ( pCtx, client, mp, pPayload, 0 );
342 
343  /*
344  * by default, clients dont recover
345  * from this
346  */
347  SEND_LOCK (client);
348  send_err (mp, ECA_INTERNAL, client, pCtx);
349  SEND_UNLOCK (client);
350 
351  return RSRV_ERROR;
352 }
353 
354 /*
355  * tcp_version_action()
356  */
357 static int tcp_version_action ( caHdrLargeArray *mp, void *pPayload,
358  struct client *client )
359 {
360  double tmp;
361  unsigned epicsPriorityNew;
362  unsigned epicsPrioritySelf;
363 
364  client->minor_version_number = mp->m_count;
365 
366  if (!CA_VSUPPORTED(mp->m_count)) {
367  DLOG ( 2, ( "CAS: Ignore version from unsupported client %u\n", mp->m_count ) );
368  return RSRV_ERROR;
369  }
370 
371  if ( mp->m_dataType > CA_PROTO_PRIORITY_MAX ) {
372  return RSRV_ERROR;
373  }
374 
375  tmp = mp->m_dataType - CA_PROTO_PRIORITY_MIN;
379  epicsPriorityNew = (unsigned) tmp;
380  epicsPrioritySelf = epicsThreadGetPrioritySelf();
381  if ( epicsPriorityNew != epicsPrioritySelf ) {
383  unsigned priorityOfEvents;
384  tbs = epicsThreadHighestPriorityLevelBelow ( epicsPriorityNew, &priorityOfEvents );
385  if ( tbs != epicsThreadBooleanStatusSuccess ) {
386  priorityOfEvents = epicsPriorityNew;
387  }
388 
389  if ( epicsPriorityNew > epicsPrioritySelf ) {
390  epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsPriorityNew );
391  db_event_change_priority ( client->evuser, priorityOfEvents );
392  }
393  else {
394  db_event_change_priority ( client->evuser, priorityOfEvents );
395  epicsThreadSetPriority ( epicsThreadGetIdSelf(), epicsPriorityNew );
396  }
397  client->priority = mp->m_dataType;
398  }
399  return RSRV_OK;
400 }
401 
402 /*
403  * tcp_echo_action()
404  */
405 static int tcp_echo_action ( caHdrLargeArray *mp,
406  void *pPayload, struct client *pClient )
407 {
408  char *pPayloadOut;
409  int status;
410  SEND_LOCK ( pClient );
411  status = cas_copy_in_header ( pClient, mp->m_cmmd, mp->m_postsize,
412  mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
413  ( void * ) &pPayloadOut );
414  if ( status == ECA_NORMAL ) {
415  memcpy ( pPayloadOut, pPayload, mp->m_postsize );
416  cas_commit_msg ( pClient, mp->m_postsize );
417  }
418  SEND_UNLOCK ( pClient );
419  return RSRV_OK;
420 }
421 
422 /*
423  * events_on_action ()
424  */
425 static int events_on_action ( caHdrLargeArray *mp,
426  void *pPayload, struct client *pClient )
427 {
428  db_event_flow_ctrl_mode_off ( pClient->evuser );
429  return RSRV_OK;
430 }
431 
432 /*
433  * events_off_action ()
434  */
435 static int events_off_action ( caHdrLargeArray *mp,
436  void *pPayload, struct client *pClient )
437 {
438  db_event_flow_ctrl_mode_on ( pClient->evuser );
439  return RSRV_OK;
440 }
441 
442 /*
443  * no_read_access_event()
444  *
445  * !! LOCK needs to applied by caller !!
446  *
447  * substantial complication introduced here by the need for backwards
448  * compatibility
449  */
450 static void no_read_access_event ( struct client *pClient,
451  struct event_ext *pevext )
452 {
453  char *pPayloadOut;
454  int status;
455 
456  /*
457  * New clients recv the status of the
458  * operation directly to the
459  * event/put/get callback.
460  *
461  * Fetched value is zerod in case they
462  * use it even when the status indicates
463  * failure.
464  *
465  * The m_cid field in the protocol
466  * header is abused to carry the status
467  */
468  status = cas_copy_in_header ( pClient, pevext->msg.m_cmmd, pevext->size,
469  pevext->msg.m_dataType, pevext->msg.m_count, ECA_NORDACCESS,
470  pevext->msg.m_available, ( void * ) &pPayloadOut );
471  if ( status == ECA_NORMAL ) {
472  memset ( pPayloadOut, 0, pevext->size );
473  cas_commit_msg ( pClient, pevext->size );
474  }
475  else {
476  send_err ( &pevext->msg, status, pClient,
477  "server unable to load read access denied response into protocol buffer PV=\"%s\" dbf=%u count=%u avail=%u max bytes=%u",
478  RECORD_NAME ( pevext->pciu->dbch ), pevext->msg.m_dataType, pevext->msg.m_count, pevext->msg.m_available, rsrvSizeofLargeBufTCP );
479  }
480 }
481 
482 /*
483  * read_reply()
484  */
485 static void read_reply ( void *pArg, struct dbChannel *dbch,
486  int eventsRemaining, db_field_log *pfl )
487 {
489  void *pPayload;
490  struct event_ext *pevext = pArg;
491  struct client *pClient = pevext->pciu->client;
492  struct channel_in_use *pciu = pevext->pciu;
493  const int readAccess = asCheckGet ( pciu->asClientPVT );
494  int status;
495  int autosize;
496  int local_fl = 0;
497  long item_count;
498  ca_uint32_t payload_size;
499  dbAddr *paddr=&dbch->addr;
500 
501  SEND_LOCK ( pClient );
502 
503  cid = ECA_NORMAL;
504 
505  /* If the client has requested a zero element count we interpret this as a
506  * request for all avaiable elements. In this case we initialise the
507  * header with the maximum element size specified by the database. */
508  autosize = pevext->msg.m_count == 0;
509  item_count =
510  autosize ? paddr->no_elements : pevext->msg.m_count;
511  payload_size = dbr_size_n(pevext->msg.m_dataType, item_count);
512  status = cas_copy_in_header(
513  pClient, pevext->msg.m_cmmd, payload_size,
514  pevext->msg.m_dataType, item_count, cid, pevext->msg.m_available,
515  &pPayload );
516  if ( status != ECA_NORMAL ) {
517  send_err ( &pevext->msg, status, pClient,
518  "server unable to load read (or subscription update) response "
519  "into protocol buffer PV=\"%s\" dbf=%u count=%ld avail=%u max bytes=%u",
520  RECORD_NAME ( dbch ), pevext->msg.m_dataType, item_count, pevext->msg.m_available, rsrvSizeofLargeBufTCP );
521  if ( ! eventsRemaining )
522  cas_send_bs_msg ( pClient, FALSE );
523  SEND_UNLOCK ( pClient );
524  return;
525  }
526 
527  /*
528  * verify read access
529  */
530  if ( ! readAccess ) {
531  no_read_access_event ( pClient, pevext );
532  if ( ! eventsRemaining )
533  cas_send_bs_msg ( pClient, FALSE );
534  SEND_UNLOCK ( pClient );
535  return;
536  }
537 
538  /* If filters are involved in a read, create field log and run filters */
539  if (!pfl && (ellCount(&dbch->pre_chain) || ellCount(&dbch->post_chain))) {
540  pfl = db_create_read_log(dbch);
541  if (pfl) {
542  local_fl = 1;
543  pfl = dbChannelRunPreChain(dbch, pfl);
544  pfl = dbChannelRunPostChain(dbch, pfl);
545  }
546  }
547 
548  status = dbChannel_get_count ( dbch, pevext->msg.m_dataType,
549  pPayload, &item_count, pfl);
550 
551  if (local_fl) db_delete_field_log(pfl);
552 
553  if ( status < 0 ) {
554  /* Clients recv the status of the operation directly to the
555  * event/put/get callback. (from CA_V41())
556  *
557  * Fetched value is set to zero in case they use it even when the
558  * status indicates failure -- unless the client selected autosizing
559  * data, in which case they'd better know what they're doing!
560  *
561  * The m_cid field in the protocol header is abused to carry the
562  * status */
563  if (autosize) {
564  payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
565  cas_set_header_count(pClient, 0);
566  }
567  memset ( pPayload, 0, payload_size );
568  cas_set_header_cid ( pClient, ECA_GETFAIL );
569  cas_commit_msg ( pClient, payload_size );
570  }
571  else {
572  int cacStatus = caNetConvert (
573  pevext->msg.m_dataType, pPayload, pPayload,
574  TRUE /* host -> net format */, item_count );
575  if ( cacStatus == ECA_NORMAL ) {
576  ca_uint32_t data_size =
577  dbr_size_n(pevext->msg.m_dataType, item_count);
578  if (autosize) {
579  payload_size = data_size;
580  cas_set_header_count(pClient, item_count);
581  }
582  else if (payload_size > data_size)
583  memset(
584  (char *) pPayload + data_size, 0, payload_size - data_size);
585  }
586  else {
587  if (autosize) {
588  payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
589  cas_set_header_count(pClient, 0);
590  }
591  memset ( pPayload, 0, payload_size );
592  cas_set_header_cid ( pClient, cacStatus );
593  }
594  cas_commit_msg ( pClient, payload_size );
595  }
596 
597  /*
598  * Ensures timely response for events, but does queue
599  * them up like db requests when the OPI does not keep up.
600  */
601  if ( ! eventsRemaining )
602  cas_send_bs_msg ( pClient, FALSE );
603 
604  SEND_UNLOCK ( pClient );
605 
606  return;
607 }
608 
609 /*
610  * read_action ()
611  */
612 static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *pClient )
613 {
614  struct channel_in_use *pciu = MPTOPCIU ( mp );
615  int readAccess;
616  ca_uint32_t payloadSize;
617  void *pPayload;
618  int status;
619  int local_fl = 0;
620  db_field_log *pfl = NULL;
621 
622  if ( ! pciu ) {
623  logBadId ( pClient, mp, 0 );
624  return RSRV_ERROR;
625  }
626  readAccess = asCheckGet ( pciu->asClientPVT );
627 
628  SEND_LOCK ( pClient );
629 
630  if ( INVALID_DB_REQ ( mp->m_dataType ) ) {
631  send_err ( mp, ECA_BADTYPE, pClient, RECORD_NAME ( pciu->dbch ) );
632  SEND_UNLOCK ( pClient );
633  return RSRV_ERROR;
634  }
635 
636  payloadSize = dbr_size_n ( mp->m_dataType, mp->m_count );
637  status = cas_copy_in_header ( pClient, mp->m_cmmd, payloadSize,
638  mp->m_dataType, mp->m_count, pciu->cid, mp->m_available, &pPayload );
639  if ( status != ECA_NORMAL ) {
640  send_err ( mp, status, pClient,
641  "server unable to load read response into protocol buffer PV=\"%s\" dbf=%u count=%u avail=%u max bytes=%u",
643  SEND_UNLOCK ( pClient );
644  return RSRV_OK;
645  }
646 
647  /*
648  * verify read access
649  */
650  if ( ! readAccess ) {
651  status = ECA_NORDACCESS;
652  send_err ( mp, status,
653  pClient, RECORD_NAME ( pciu->dbch ) );
654  SEND_UNLOCK ( pClient );
655  return RSRV_OK;
656  }
657 
658  /* If filters are involved in a read, create field log and run filters */
659  if (ellCount(&pciu->dbch->pre_chain) || ellCount(&pciu->dbch->post_chain)) {
660  pfl = db_create_read_log(pciu->dbch);
661  if (pfl) {
662  local_fl = 1;
663  pfl = dbChannelRunPreChain(pciu->dbch, pfl);
664  pfl = dbChannelRunPostChain(pciu->dbch, pfl);
665  }
666  }
667 
668  status = dbChannel_get ( pciu->dbch, mp->m_dataType,
669  pPayload, mp->m_count, pfl );
670 
671  if (local_fl) db_delete_field_log(pfl);
672 
673  if ( status < 0 ) {
674  send_err ( mp, ECA_GETFAIL, pClient, RECORD_NAME ( pciu->dbch ) );
675  SEND_UNLOCK ( pClient );
676  return RSRV_OK;
677  }
678 
679  status = caNetConvert (
680  mp->m_dataType, pPayload, pPayload,
681  TRUE /* host -> net format */, mp->m_count );
682  if ( status != ECA_NORMAL ) {
683  send_err ( mp, status, pClient, RECORD_NAME ( pciu->dbch ) );
684  SEND_UNLOCK ( pClient );
685  return RSRV_OK;
686  }
687 
688  /*
689  * force string message size to be the true size rounded to even
690  * boundary
691  */
692  if ( mp->m_dataType == DBR_STRING && mp->m_count == 1 ) {
693  char * pStr = (char *) pPayload;
694  size_t strcnt = epicsStrnLen( pStr, payloadSize );
695  if ( strcnt < payloadSize ) {
696  payloadSize = ( ca_uint32_t ) ( strcnt + 1u );
697  }
698  else {
699  pStr[payloadSize-1] = '\0';
700  errlogPrintf (
701  "caserver: read_action: detected DBR_STRING w/o nill termination "
702  "in response from db_get_field, pPayload = \"%s\"\n",
703  pStr );
704  }
705  }
706  cas_commit_msg ( pClient, payloadSize );
707 
708  SEND_UNLOCK ( pClient );
709 
710  return RSRV_OK;
711 }
712 
713 /*
714  * read_notify_action()
715  */
716 static int read_notify_action ( caHdrLargeArray *mp, void *pPayload, struct client *client )
717 {
718  struct channel_in_use *pciu;
719  struct event_ext evext;
720 
721  if ( INVALID_DB_REQ(mp->m_dataType) ) {
722  return RSRV_ERROR;
723  }
724 
725  pciu = MPTOPCIU ( mp );
726  if ( !pciu ) {
727  logBadId ( client, mp, pPayload );
728  return RSRV_ERROR;
729  }
730 
731  evext.msg = *mp;
732  evext.pciu = pciu;
733  evext.pdbev = NULL;
734  evext.size = dbr_size_n ( mp->m_dataType, mp->m_count );
735 
736  /*
737  * Arguments to this routine organized in
738  * favor of the standard db event calling
739  * mechanism- routine(userarg, paddr). See
740  * events added above.
741  *
742  * Hold argument set true so the send message
743  * buffer is not flushed once each call.
744  */
745  read_reply ( &evext, pciu->dbch, TRUE, NULL );
746 
747  return RSRV_OK;
748 }
749 
750 /*
751  * write_action()
752  */
753 static int write_action ( caHdrLargeArray *mp,
754  void *pPayload, struct client *client )
755 {
756  struct channel_in_use *pciu;
757  int status;
758  long dbStatus;
759  void *asWritePvt;
760 
761  pciu = MPTOPCIU(mp);
762  if(!pciu){
763  logBadId(client, mp, pPayload);
764  return RSRV_ERROR;
765  }
766 
767  if(!rsrvCheckPut(pciu)){
768  status = ECA_NOWTACCESS;
769  SEND_LOCK(client);
770  send_err(
771  mp,
772  status,
773  client,
774  RECORD_NAME ( pciu->dbch ));
775  SEND_UNLOCK(client);
776  return RSRV_OK;
777  }
778 
779  status = caNetConvert (
780  mp->m_dataType, pPayload, pPayload,
781  FALSE /* net -> host format */, mp->m_count );
782  if ( status != ECA_NORMAL ) {
783  log_header ("invalid data type", client, mp, pPayload, 0);
784  SEND_LOCK(client);
785  send_err(
786  mp,
787  status,
788  client,
789  RECORD_NAME ( pciu->dbch ));
790  SEND_UNLOCK(client);
791  return RSRV_ERROR;
792  }
793 
794  asWritePvt = asTrapWriteWithData ( pciu->asClientPVT,
795  pciu->client->pUserName ? pciu->client->pUserName : "",
796  pciu->client->pHostName ? pciu->client->pHostName : "",
797  pciu->dbch, mp->m_dataType, mp->m_count, pPayload );
798 
799  dbStatus = dbChannel_put(
800  pciu->dbch,
801  mp->m_dataType,
802  pPayload,
803  mp->m_count);
804 
805  asTrapWriteAfter(asWritePvt);
806 
807  if (dbStatus < 0) {
808  SEND_LOCK(client);
809  send_err(
810  mp,
811  ECA_PUTFAIL,
812  client,
813  RECORD_NAME ( pciu->dbch ));
814  SEND_UNLOCK(client);
815  }
816 
817  return RSRV_OK;
818 }
819 
820 /*
821  * host_name_action()
822  */
823 static int host_name_action ( caHdrLargeArray *mp, void *pPayload,
824  struct client *client )
825 {
826  ca_uint32_t size;
827  char *pName;
828  char *pMalloc;
829  int chanCount;
830 
831  epicsMutexMustLock ( client->chanListLock );
832  chanCount =
833  ellCount ( &client->chanList ) +
834  ellCount ( &client->chanPendingUpdateARList );
835  epicsMutexUnlock( client->chanListLock );
836 
837  if ( chanCount != 0 ) {
838  SEND_LOCK ( client );
839  send_err(
840  mp,
841  ECA_INTERNAL,
842  client,
843  "attempts to use protocol to set host name "
844  "after creating first channel ignored by server" );
845  SEND_UNLOCK ( client );
846  return RSRV_OK;
847  }
848 
849  pName = (char *) pPayload;
850  size = epicsStrnLen(pName, mp->m_postsize)+1;
851  if (size > 512 || size > mp->m_postsize) {
852  log_header ( "bad (very long) host name",
853  client, mp, pPayload, 0 );
854  SEND_LOCK(client);
855  send_err(
856  mp,
857  ECA_INTERNAL,
858  client,
859  "bad (very long) host name");
860  SEND_UNLOCK(client);
861  return RSRV_ERROR;
862  }
863 
864  /* after all validation */
865  if(asCheckClientIP) {
866 
867  DLOG (2, ( "CAS: host_name_action for \"%s\" ignores client provided host name\n",
868  client->pHostName ) );
869  return RSRV_OK;
870  }
871 
872  /*
873  * user name will not change if there isnt enough memory
874  */
875  pMalloc = malloc(size);
876  if(!pMalloc){
877  log_header ( "no space in pool for new host name",
878  client, mp, pPayload, 0 );
879  SEND_LOCK(client);
880  send_err(
881  mp,
882  ECA_ALLOCMEM,
883  client,
884  "no space in pool for new host name");
885  SEND_UNLOCK(client);
886  return RSRV_ERROR;
887  }
888  strncpy(
889  pMalloc,
890  pName,
891  size-1);
892  pMalloc[size-1]='\0';
893 
894  pName = client->pHostName;
895  client->pHostName = pMalloc;
896  if ( pName ) {
897  free ( pName );
898  }
899 
900  DLOG (2, ( "CAS: host_name_action for \"%s\"\n",
901  client->pHostName ? client->pHostName : "" ) );
902 
903  return RSRV_OK;
904 }
905 
906 
907 /*
908  * client_name_action()
909  */
910 static int client_name_action ( caHdrLargeArray *mp, void *pPayload,
911  struct client *client )
912 {
913  ca_uint32_t size;
914  char *pName;
915  char *pMalloc;
916  int chanCount;
917 
918  epicsMutexMustLock ( client->chanListLock );
919  chanCount =
920  ellCount ( &client->chanList ) +
921  ellCount ( &client->chanPendingUpdateARList );
922  epicsMutexUnlock( client->chanListLock );
923 
924  if ( chanCount != 0 ) {
925  SEND_LOCK ( client );
926  send_err(
927  mp,
928  ECA_INTERNAL,
929  client,
930  "attempts to use protocol to set user name "
931  "after creating first channel ignored by server" );
932  SEND_UNLOCK ( client );
933  return RSRV_OK;
934  }
935 
936  pName = (char *) pPayload;
937  size = epicsStrnLen(pName, mp->m_postsize)+1;
938  if (size > 512 || size > mp->m_postsize) {
939  log_header ("a very long user name was specified",
940  client, mp, pPayload, 0);
941  SEND_LOCK(client);
942  send_err(
943  mp,
944  ECA_INTERNAL,
945  client,
946  "a very long user name was specified");
947  SEND_UNLOCK(client);
948  return RSRV_ERROR;
949  }
950 
951  /*
952  * user name will not change if there isnt enough memory
953  */
954  pMalloc = malloc(size);
955  if(!pMalloc){
956  log_header ("no memory for new user name",
957  client, mp, pPayload, 0);
958  SEND_LOCK(client);
959  send_err(
960  mp,
961  ECA_ALLOCMEM,
962  client,
963  "no memory for new user name");
964  SEND_UNLOCK(client);
965  return RSRV_ERROR;
966  }
967  strncpy(
968  pMalloc,
969  pName,
970  size-1);
971  pMalloc[size-1]='\0';
972 
973  pName = client->pUserName;
974  client->pUserName = pMalloc;
975  if ( pName ) {
976  free ( pName );
977  }
978 
979  return RSRV_OK;
980 }
981 
982 /*
983  * casCreateChannel ()
984  */
985 static struct channel_in_use *casCreateChannel (
986 struct client *client,
987 struct dbChannel *dbch,
988 unsigned cid
989 )
990 {
991  static unsigned bucketID;
992  unsigned *pCID;
993  struct channel_in_use *pchannel;
994  int status;
995 
996  /* get block off free list if possible */
997  pchannel = (struct channel_in_use *)
999  if (!pchannel) {
1000  return NULL;
1001  }
1002  ellInit(&pchannel->eventq);
1004  pchannel->dbch = dbch;
1005  pchannel->client = client;
1006  /*
1007  * bypass read only warning
1008  */
1009  pCID = (unsigned *) &pchannel->cid;
1010  *pCID = cid;
1011 
1012  /*
1013  * allocate a server id and enter the channel pointer
1014  * in the table
1015  *
1016  * NOTE: This detects the case where the PV id wraps
1017  * around and we attempt to have two resources on the same id.
1018  * The lock is applied here because on some architectures the
1019  * ++ operator isnt atomic.
1020  */
1021  LOCK_CLIENTQ;
1022 
1023  do {
1024  /*
1025  * bypass read only warning
1026  */
1027  pCID = (unsigned *) &pchannel->sid;
1028  *pCID = bucketID++;
1029 
1030  /*
1031  * Verify that this id is not in use
1032  */
1033  status = bucketAddItemUnsignedId (
1034  pCaBucket,
1035  &pchannel->sid,
1036  pchannel);
1037  } while (status == S_bucket_idInUse);
1038 
1039  if ( status == S_bucket_success ) {
1040  rsrvChannelCount++;
1041  }
1042 
1044 
1045  if(status!=S_bucket_success){
1046  freeListFree(rsrvChanFreeList, pchannel);
1047  errMessage (status, "Unable to allocate server id");
1048  return NULL;
1049  }
1050 
1051  epicsMutexMustLock( client->chanListLock );
1052  pchannel->state = rsrvCS_pendConnectResp;
1053  ellAdd ( &client->chanList, &pchannel->node );
1054  epicsMutexUnlock ( client->chanListLock );
1055 
1056  return pchannel;
1057 }
1058 
1059 /*
1060  * casAccessRightsCB()
1061  *
1062  * If access right state changes then inform the client.
1063  * asLock is held
1064  */
1065 static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
1066 {
1067  struct client * pclient;
1068  struct channel_in_use * pciu;
1069  struct event_ext * pevext;
1070 
1071  pciu = asGetClientPvt(ascpvt);
1072  assert(pciu);
1073 
1074  pclient = pciu->client;
1075  assert(pclient);
1076 
1077  if(pclient->proto==IPPROTO_UDP){
1078  return;
1079  }
1080 
1081  switch(type)
1082  {
1083  case asClientCOAR:
1084  {
1085  const int readAccess = asCheckGet ( pciu->asClientPVT );
1086  unsigned sigReq = 0;
1087 
1088  epicsMutexMustLock ( pclient->chanListLock );
1089  if ( pciu->state == rsrvCS_pendConnectResp ) {
1090  ellDelete ( &pclient->chanList, &pciu->node );
1092  ellAdd ( &pclient->chanPendingUpdateARList, &pciu->node );
1093  sigReq = 1;
1094  }
1095  else if ( pciu->state == rsrvCS_inService ) {
1096  ellDelete ( &pclient->chanList, &pciu->node );
1098  ellAdd ( &pclient->chanPendingUpdateARList, &pciu->node );
1099  sigReq = 1;
1100  }
1101  epicsMutexUnlock ( pclient->chanListLock );
1102 
1103  /*
1104  * Update all event call backs
1105  */
1106  epicsMutexMustLock(pclient->eventqLock);
1107  for (pevext = (struct event_ext *) ellFirst(&pciu->eventq);
1108  pevext;
1109  pevext = (struct event_ext *) ellNext(&pevext->node)){
1110 
1111  if ( pevext->pdbev ) {
1112  if ( readAccess ){
1113  db_event_enable ( pevext->pdbev );
1114  db_post_single_event ( pevext->pdbev );
1115  }
1116  else {
1117  db_post_single_event ( pevext->pdbev );
1118  db_event_disable ( pevext->pdbev );
1119  }
1120  }
1121  }
1122  epicsMutexUnlock(pclient->eventqLock);
1123 
1124  if ( sigReq ) {
1125  db_post_extra_labor( pclient->evuser );
1126  }
1127 
1128  break;
1129  }
1130  default:
1131  break;
1132  }
1133 }
1134 
1135 /*
1136  * access_rights_reply()
1137  */
1138 static void access_rights_reply ( struct channel_in_use * pciu )
1139 {
1140  unsigned ar;
1141  int status;
1142 
1143  assert ( pciu->client->proto!=IPPROTO_UDP );
1144 
1145  ar = 0; /* none */
1146  if ( asCheckGet ( pciu->asClientPVT ) ) {
1148  }
1149  if ( rsrvCheckPut ( pciu ) ) {
1151  }
1152 
1153  SEND_LOCK ( pciu->client );
1154  status = cas_copy_in_header (
1155  pciu->client, CA_PROTO_ACCESS_RIGHTS, 0,
1156  0, 0, pciu->cid, ar, 0 );
1157  /*
1158  * OK to just ignore the request if the connection drops
1159  */
1160  if ( status == ECA_NORMAL ) {
1161  cas_commit_msg ( pciu->client, 0u );
1162  }
1163  SEND_UNLOCK ( pciu->client );
1164 }
1165 
1166 /*
1167  * claim_ciu_reply()
1168  */
1169 static void claim_ciu_reply ( struct channel_in_use * pciu )
1170 {
1171  int status;
1172  ca_uint32_t nElem;
1173  long dbElem;
1174 
1175  access_rights_reply ( pciu );
1176 
1177  SEND_LOCK ( pciu->client );
1178  dbElem = dbChannelFinalElements(pciu->dbch);
1179  if ( dbElem < 0 ) {
1180  nElem = 0;
1181  }
1182  else {
1183  if ( ! CA_V49 ( pciu->client->minor_version_number ) ) {
1184  if ( dbElem >= 0xffff ) {
1185  nElem = 0xfffe;
1186  }
1187  else {
1188  nElem = (ca_uint32_t) dbElem;
1189  }
1190  }
1191  else {
1192  nElem = (ca_uint32_t) dbElem;
1193  }
1194  }
1195  status = cas_copy_in_header (
1196  pciu->client, CA_PROTO_CREATE_CHAN, 0u,
1197  dbChannelFinalCAType(pciu->dbch), nElem, pciu->cid,
1198  pciu->sid, NULL );
1199  if ( status == ECA_NORMAL ) {
1200  cas_commit_msg ( pciu->client, 0u );
1201  }
1202  SEND_UNLOCK(pciu->client);
1203 }
1204 
1205 /*
1206  * claim_ciu_action()
1207  */
1208 static int claim_ciu_action ( caHdrLargeArray *mp,
1209  void *pPayload, client *client )
1210 {
1211  int status;
1212  struct channel_in_use *pciu;
1213  struct dbChannel *dbch;
1214  char *pName = (char *) pPayload;
1215 
1216  /*
1217  * The available field is used (abused)
1218  * here to communicate the miner version number
1219  * starting with CA 4.1. The field was set to zero
1220  * prior to 4.1
1221  */
1222  client->minor_version_number = mp->m_available;
1223 
1224  if (!CA_V44(client->minor_version_number))
1225  return RSRV_ERROR; /* shouldn't actually get here due to VSUPPORTED test in camessage() */
1226 
1227  /*
1228  * check the sanity of the message
1229  */
1230  if (mp->m_postsize<=1) {
1231  log_header ( "empty PV name in UDP search request?",
1232  client, mp, pPayload, 0 );
1233  return RSRV_OK;
1234  }
1235  pName[mp->m_postsize-1] = '\0';
1236 
1237  dbch = dbChannel_create (pName);
1238  if (!dbch) {
1239  SEND_LOCK(client);
1240  status = cas_copy_in_header ( client,
1241  CA_PROTO_CREATE_CH_FAIL, 0, 0, 0, mp->m_cid, 0, NULL );
1242  if (status == ECA_NORMAL)
1243  cas_commit_msg ( client, 0u );
1244  SEND_UNLOCK(client);
1245  return RSRV_OK;
1246  }
1247 
1248  DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
1249  pName, dbChannelCAType(dbch), dbChannelElements(dbch)) );
1250 
1251  pciu = casCreateChannel (
1252  client,
1253  dbch,
1254  mp->m_cid);
1255  if (!pciu) {
1256  log_header ("no memory to create new channel",
1257  client, mp, pPayload, 0);
1258  SEND_LOCK(client);
1259  send_err(mp,
1260  ECA_ALLOCMEM,
1261  client,
1262  RECORD_NAME(dbch));
1263  SEND_UNLOCK(client);
1264  dbChannelDelete(dbch);
1265  return RSRV_ERROR;
1266  }
1267 
1268  /*
1269  * set up access security for this channel
1270  */
1271  status = asAddClient(
1272  &pciu->asClientPVT,
1273  asDbGetMemberPvt(pciu->dbch),
1274  asDbGetAsl(pciu->dbch),
1275  client->pUserName ? client->pUserName : "",
1276  client->pHostName ? client->pHostName : "");
1277  if(status != 0 && status != S_asLib_asNotActive){
1278  log_header ("No room for security table",
1279  client, mp, pPayload, 0);
1280  SEND_LOCK(client);
1281  send_err(mp, ECA_ALLOCMEM, client, "No room for security table");
1282  SEND_UNLOCK(client);
1283  return RSRV_ERROR;
1284  }
1285 
1286  /*
1287  * store ptr to channel in use block
1288  * in access security private
1289  */
1290  asPutClientPvt(pciu->asClientPVT, pciu);
1291 
1292  /*
1293  * register for asynch updates of access rights changes
1294  */
1295  status = asRegisterClientCallback(
1296  pciu->asClientPVT,
1297  casAccessRightsCB);
1298  if ( status == S_asLib_asNotActive ) {
1299  epicsMutexMustLock ( client->chanListLock );
1300  pciu->state = rsrvCS_inService;
1301  epicsMutexUnlock ( client->chanListLock );
1302  /*
1303  * force the initial AR update followed by claim response
1304  */
1305  claim_ciu_reply ( pciu );
1306  }
1307  else if (status!=0) {
1308  log_header ("No room for access security state change subscription",
1309  client, mp, pPayload, 0);
1310  SEND_LOCK(client);
1311  send_err(mp, ECA_ALLOCMEM, client,
1312  "No room for access security state change subscription");
1313  SEND_UNLOCK(client);
1314  return RSRV_ERROR;
1315  }
1316  return RSRV_OK;
1317 }
1318 
1319 /*
1320  * write_notify_put_callback()
1321  *
1322  * (called by the db call back thread)
1323  */
1324  LOCAL int write_notify_put_callback(processNotify *ppn,notifyPutType type)
1325  {
1326  struct channel_in_use * pciu = (struct channel_in_use *) ppn->usrPvt;
1327  struct rsrv_put_notify *pNotify;
1328 
1329  if(ppn->status==notifyCanceled) return 0;
1330  /*
1331  * No locking in this method because only a dbNotifyCancel could interrupt
1332  * and it does not return until cancel is done.
1333  */
1334  assert(pciu);
1335  assert(pciu->pPutNotify);
1336  pNotify = pciu->pPutNotify;
1337  return db_put_process(ppn,type,
1338  pNotify->dbrType,pNotify->pbuffer,pNotify->nRequest);
1339  }
1340 
1341  /*
1342  * write_notify_done_callback()
1343  *
1344  * (called by the db call back thread)
1345  */
1346  LOCAL void write_notify_done_callback(processNotify *ppn)
1347 {
1348  struct channel_in_use * pciu = (struct channel_in_use *) ppn->usrPvt;
1349  struct client * pClient;
1350 
1351  /*
1352  * independent lock used here in order to
1353  * avoid any possibility of blocking
1354  * the database (or indirectly blocking
1355  * one client on another client).
1356  */
1357  assert(pciu);
1358  assert(pciu->pPutNotify);
1359  pClient = pciu->client;
1361 
1362  if ( ! pciu->pPutNotify->busy || pciu->pPutNotify->onExtraLaborQueue ) {
1363  epicsMutexUnlock(pClient->putNotifyLock);
1364  errlogPrintf("Double DB put notify call back!!\n");
1365  return;
1366  }
1367 
1368  ellAdd(&pClient->putNotifyQue, &pciu->pPutNotify->node);
1370 
1371  epicsMutexUnlock(pClient->putNotifyLock);
1372 
1373  /*
1374  * offload the labor for this to the
1375  * event task so that we never block
1376  * the db or another client.
1377  */
1378  db_post_extra_labor(pClient->evuser);
1379 }
1380 
1381 /*
1382  * write_notify_reply()
1383  * (called by the CA server event task via the extra labor interface)
1384  */
1385 static void write_notify_reply ( struct client * pClient )
1386 {
1387  while(TRUE){
1388  caHdrLargeArray msgtmp;
1389  void * asWritePvtTmp;
1391  int localStatus;
1392 
1393  /*
1394  * independent lock used here in order to
1395  * avoid any possibility of blocking
1396  * the database (or indirectly blocking
1397  * one client on another client).
1398  */
1400  {
1401  RSRVPUTNOTIFY * ppnb = (RSRVPUTNOTIFY *)
1402  ellGet ( &pClient->putNotifyQue );
1403  if ( ! ppnb ) {
1404  epicsMutexUnlock(pClient->putNotifyLock);
1405  break;
1406  }
1407  /*
1408  *
1409  * Map from DB status to CA status
1410  *
1411  */
1412  if ( ppnb->dbPutNotify.status != notifyOK ) {
1413  status = ECA_PUTFAIL;
1414  }
1415  else{
1416  status = ECA_NORMAL;
1417  }
1418  msgtmp = ppnb->msg;
1419  asWritePvtTmp = ppnb->asWritePvt;
1420  ppnb->asWritePvt = 0;
1421  ppnb->onExtraLaborQueue = FALSE;
1422  ppnb->busy = FALSE;
1423  }
1424  epicsMutexUnlock(pClient->putNotifyLock);
1425 
1426  asTrapWriteAfter ( asWritePvtTmp );
1427 
1428  /*
1429  * the channel id field is being abused to carry
1430  * status here
1431  */
1432  SEND_LOCK(pClient);
1433  localStatus = cas_copy_in_header (
1434  pClient, CA_PROTO_WRITE_NOTIFY,
1435  0u, msgtmp.m_dataType, msgtmp.m_count, status,
1436  msgtmp.m_available, 0 );
1437  if ( localStatus != ECA_NORMAL ) {
1438  /*
1439  * inability to aquire buffer space
1440  * Indicates corruption
1441  */
1442  errlogPrintf("CA server corrupted - put call back(s) discarded\n");
1443  SEND_UNLOCK ( pClient );
1444  break;
1445  }
1446 
1447  /* commit the message */
1448  cas_commit_msg ( pClient, 0u );
1449  SEND_UNLOCK ( pClient );
1450  }
1451 
1452  /*
1453  * wakeup the TCP thread if it is waiting for a cb to complete
1454  */
1455  epicsEventSignal ( pClient->blockSem );
1456 }
1457 
1458 /*
1459  * sendAllUpdateAS()
1460  */
1461 static void sendAllUpdateAS ( struct client *client )
1462 {
1463  struct channel_in_use *pciu;
1464 
1465  epicsMutexMustLock ( client->chanListLock );
1466 
1467  pciu = ( struct channel_in_use * )
1468  ellGet ( & client->chanPendingUpdateARList );
1469  while ( pciu ) {
1470  if ( pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) {
1471  claim_ciu_reply ( pciu );
1472  }
1473  else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ) {
1474  access_rights_reply ( pciu );
1475  }
1476  else if ( pciu->state == rsrvCS_shutdown ) {
1477  /* no-op */
1478  }
1479  else {
1480  errlogPrintf (
1481  "%s at %d: corrupt channel state detected durring AR update\n",
1482  __FILE__, __LINE__);
1483  }
1484  pciu->state = rsrvCS_inService;
1485  ellAdd ( & client->chanList, & pciu->node );
1486  pciu = ( struct channel_in_use * )
1487  ellGet ( & client->chanPendingUpdateARList );
1488  }
1489 
1490  epicsMutexUnlock( client->chanListLock );
1491 }
1492 
1493 /*
1494  * rsrv_extra_labor()
1495  * (called by the CA server event task via the extra labor interface)
1496  */
1497 void rsrv_extra_labor ( void * pArg )
1498 {
1499  struct client * pClient = pArg;
1500  write_notify_reply ( pClient );
1501  sendAllUpdateAS ( pClient );
1502  cas_send_bs_msg ( pClient, TRUE );
1503 }
1504 
1505 /*
1506  * putNotifyErrorReply
1507  */
1508 static void putNotifyErrorReply ( struct client *client, caHdrLargeArray *mp, int statusCA )
1509 {
1510  int status;
1511 
1512  SEND_LOCK ( client );
1513  /*
1514  * the cid field abused to contain status
1515  * during put cb replies
1516  */
1517  status = cas_copy_in_header ( client, CA_PROTO_WRITE_NOTIFY,
1518  0u, mp->m_dataType, mp->m_count, statusCA,
1519  mp->m_available, 0 );
1520  if ( status != ECA_NORMAL ) {
1521  SEND_UNLOCK ( client );
1522  errlogPrintf ("%s at %d: should always get sufficent space for put notify error reply\n",
1523  __FILE__, __LINE__);
1524  return;
1525  }
1526  cas_commit_msg ( client, 0u );
1527  SEND_UNLOCK ( client );
1528 }
1529 
1531 {
1532  if ( ! rsrvPutNotifyFreeList ) {
1534  sizeof(struct rsrv_put_notify), 512 );
1536  }
1537 }
1538 
1539 static struct rsrv_put_notify *
1540  rsrvAllocPutNotify ( struct channel_in_use * pciu )
1541 {
1542  struct rsrv_put_notify *pNotify;
1543 
1544  if ( rsrvPutNotifyFreeList ) {
1545  pNotify = (RSRVPUTNOTIFY *)
1547  if ( pNotify ) {
1548  pNotify->pbuffer = &pNotify->dbrScalarValue;
1549  pNotify->valueSize =
1550  sizeof (pNotify->dbrScalarValue);
1551  pNotify->dbPutNotify.usrPvt = pciu;
1552  pNotify->dbPutNotify.chan = pciu->dbch;
1553  pNotify->dbPutNotify.putCallback =
1555  pNotify->dbPutNotify.doneCallback =
1557  pNotify->dbPutNotify.requestType = putProcessRequest;
1558  }
1559  }
1560  else {
1561  pNotify = NULL;
1562  }
1563  return pNotify;
1564 }
1565 
1566 static int rsrvExpandPutNotify (
1567  struct rsrv_put_notify * pNotify, unsigned sizeNeeded )
1568 {
1569  int booleanStatus;
1570 
1571  if ( sizeNeeded > pNotify->valueSize ) {
1572  /*
1573  * try to use the union embeded in the free list
1574  * item, but allocate a random sized block if they
1575  * writing a vector.
1576  */
1577  if ( pNotify->valueSize >
1578  sizeof (pNotify->dbrScalarValue) ) {
1579  free ( pNotify->pbuffer );
1580  }
1581  pNotify->pbuffer = casCalloc(1,sizeNeeded);
1582  if ( pNotify->pbuffer ) {
1583  pNotify->valueSize = sizeNeeded;
1584  booleanStatus = TRUE;
1585  }
1586  else {
1587  /*
1588  * revert back to the embedded union
1589  */
1590  pNotify->pbuffer =
1591  &pNotify->dbrScalarValue;
1592  pNotify->valueSize =
1593  sizeof (pNotify->dbrScalarValue);
1594  booleanStatus = FALSE;
1595  }
1596  }
1597  else {
1598  booleanStatus = TRUE;
1599  }
1600 
1601  return booleanStatus;
1602 }
1603 
1604 unsigned rsrvSizeOfPutNotify ( struct rsrv_put_notify *pNotify )
1605 {
1606  unsigned size = sizeof ( *pNotify );
1607  if ( pNotify ) {
1608  if ( pNotify->valueSize >
1609  sizeof ( pNotify->dbrScalarValue ) ) {
1610  size += pNotify->valueSize;
1611  }
1612  }
1613  return size;
1614 }
1615 
1616 void rsrvFreePutNotify ( client *pClient,
1617  struct rsrv_put_notify *pNotify )
1618 {
1619  if ( pNotify ) {
1620  char busyTmp;
1621  void * asWritePvtTmp = 0;
1622 
1623  epicsMutexMustLock ( pClient->putNotifyLock );
1624  busyTmp = pNotify->busy;
1625  epicsMutexUnlock ( pClient->putNotifyLock );
1626 
1627  /*
1628  * if any possiblity that the put notify is
1629  * outstanding then cancel it
1630  */
1631  if ( busyTmp ) {
1632  dbNotifyCancel ( &pNotify->dbPutNotify );
1633  }
1634 
1635  epicsMutexMustLock ( pClient->putNotifyLock );
1636  if ( pNotify->onExtraLaborQueue ) {
1637  ellDelete ( &pClient->putNotifyQue,
1638  &pNotify->node );
1639  }
1640  busyTmp = pNotify->busy;
1641  asWritePvtTmp = pNotify->asWritePvt;
1642  pNotify->asWritePvt = 0;
1643  epicsMutexUnlock ( pClient->putNotifyLock );
1644 
1645  if ( busyTmp ) {
1646  asTrapWriteAfter ( asWritePvtTmp );
1647  }
1648 
1649  if ( pNotify->valueSize >
1650  sizeof(pNotify->dbrScalarValue) ) {
1651  free ( pNotify->pbuffer );
1652  }
1653  freeListFree ( rsrvPutNotifyFreeList, pNotify );
1654  }
1655 }
1656 
1657 /*
1658  * write_notify_action()
1659  */
1660 static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
1661  struct client *client )
1662 {
1663  unsigned size;
1664  int status;
1665  struct channel_in_use *pciu;
1666 
1667  pciu = MPTOPCIU(mp);
1668  if(!pciu){
1669  logBadId ( client, mp, pPayload );
1670  return RSRV_ERROR;
1671  }
1672 
1673  if (mp->m_dataType > LAST_BUFFER_TYPE) {
1674  log_header ("bad put notify data type", client, mp, pPayload, 0);
1675  putNotifyErrorReply (client, mp, ECA_BADTYPE);
1676  return RSRV_ERROR;
1677  }
1678 
1679  if(!rsrvCheckPut(pciu)){
1680  putNotifyErrorReply (client, mp, ECA_NOWTACCESS);
1681  return RSRV_OK;
1682  }
1683 
1684  size = dbr_size_n (mp->m_dataType, mp->m_count);
1685 
1686  if ( pciu->pPutNotify ) {
1687 
1688  /*
1689  * serialize concurrent put notifies
1690  */
1692  while(pciu->pPutNotify->busy){
1694  status = epicsEventWaitWithTimeout(client->blockSem,60.0);
1695  if ( status != epicsEventWaitOK ) {
1696  char busyTmp;
1697  void * asWritePvtTmp = 0;
1698 
1700  busyTmp = pciu->pPutNotify->busy;
1702 
1703  /*
1704  * if any possibility of put notify still running
1705  * then cancel it
1706  */
1707  if ( busyTmp ) {
1708  dbNotifyCancel(&pciu->pPutNotify->dbPutNotify);
1709  }
1711  busyTmp = pciu->pPutNotify->busy;
1712  if ( busyTmp ) {
1713  if ( pciu->pPutNotify->onExtraLaborQueue ) {
1714  ellDelete ( &client->putNotifyQue,
1715  &pciu->pPutNotify->node );
1716  }
1717  pciu->pPutNotify->busy = FALSE;
1718  asWritePvtTmp = pciu->pPutNotify->asWritePvt;
1719  pciu->pPutNotify->asWritePvt = 0;
1720  }
1722 
1723  if ( busyTmp ) {
1724  log_header("put call back time out", client,
1725  &pciu->pPutNotify->msg, pciu->pPutNotify->pbuffer, 0);
1726  asTrapWriteAfter ( asWritePvtTmp );
1727  putNotifyErrorReply (client, &pciu->pPutNotify->msg, ECA_PUTCBINPROG);
1728  }
1729  }
1731  }
1733  }
1734  else {
1735  pciu->pPutNotify = rsrvAllocPutNotify ( pciu );
1736  if ( ! pciu->pPutNotify ) {
1737  /*
1738  * send error and go to next request
1739  * if there isnt enough memory left
1740  */
1741  log_header ( "no memory to initiate put notify",
1742  client, mp, pPayload, 0 );
1743  putNotifyErrorReply (client, mp, ECA_ALLOCMEM);
1744  return RSRV_ERROR;
1745  }
1746  }
1747 
1748  if ( ! rsrvExpandPutNotify ( pciu->pPutNotify, size ) ) {
1749  log_header ( "no memory to initiate vector put notify",
1750  client, mp, pPayload, 0 );
1751  putNotifyErrorReply ( client, mp, ECA_ALLOCMEM );
1752  return RSRV_ERROR;
1753  }
1754 
1755  pciu->pPutNotify->busy = TRUE;
1757  pciu->pPutNotify->msg = *mp;
1758  pciu->pPutNotify->nRequest = mp->m_count;
1759 
1760  status = caNetConvert (
1761  mp->m_dataType, pPayload, pciu->pPutNotify->pbuffer,
1762  FALSE /* net -> host format */, mp->m_count );
1763  if ( status != ECA_NORMAL ) {
1764  log_header ("invalid data type", client, mp, pPayload, 0);
1765  putNotifyErrorReply ( client, mp, status );
1766  return RSRV_ERROR;
1767  }
1768 
1769  pciu->pPutNotify->dbrType = mp->m_dataType;
1770 
1772  pciu->asClientPVT,
1773  pciu->client->pUserName ? pciu->client->pUserName : "",
1774  pciu->client->pHostName ? pciu->client->pHostName : "",
1775  pciu->dbch, mp->m_dataType, mp->m_count,
1776  pciu->pPutNotify->pbuffer );
1777 
1778  dbProcessNotify(&pciu->pPutNotify->dbPutNotify);
1779 
1780  return RSRV_OK;
1781 }
1782 
1783 /*
1784  *
1785  * event_add_action()
1786  *
1787  */
1788 static int event_add_action (caHdrLargeArray *mp, void *pPayload, struct client *client)
1789 {
1790  struct mon_info *pmi = (struct mon_info *) pPayload;
1791  int spaceAvailOnFreeList;
1792  struct channel_in_use *pciu;
1793  struct event_ext *pevext;
1794 
1795  if ( INVALID_DB_REQ(mp->m_dataType) ) {
1796  return RSRV_ERROR;
1797  }
1798 
1799  pciu = MPTOPCIU ( mp );
1800  if ( ! pciu ) {
1801  logBadId ( client, mp, pPayload );
1802  return RSRV_ERROR;
1803  }
1804 
1805  /*
1806  * stop further use of server if memory becomes scarce
1807  */
1808  spaceAvailOnFreeList = freeListItemsAvail ( rsrvEventFreeList ) > 0;
1809  if ( osiSufficentSpaceInPool(sizeof(*pevext)) || spaceAvailOnFreeList ) {
1810  pevext = (struct event_ext *) freeListCalloc (rsrvEventFreeList);
1811  }
1812  else {
1813  pevext = 0;
1814  }
1815 
1816  if (!pevext) {
1817  log_header ("no memory to add subscription",
1818  client, mp, pPayload, 0);
1819  SEND_LOCK(client);
1820  send_err(
1821  mp,
1822  ECA_ALLOCMEM,
1823  client,
1824  RECORD_NAME(pciu->dbch));
1825  SEND_UNLOCK(client);
1826  return RSRV_ERROR;
1827  }
1828 
1829  pevext->msg = *mp;
1830  pevext->pciu = pciu;
1831  pevext->size = dbr_size_n(mp->m_dataType, mp->m_count);
1832  pevext->mask = ntohs ( pmi->m_mask );
1833 
1834  epicsMutexMustLock(client->eventqLock);
1835  ellAdd( &pciu->eventq, &pevext->node);
1836  epicsMutexUnlock(client->eventqLock);
1837 
1838  pevext->pdbev = db_add_event (client->evuser, pciu->dbch,
1839  read_reply, pevext, pevext->mask);
1840  if (pevext->pdbev == NULL) {
1841  log_header ("no memory to add subscription to db",
1842  client, mp, pPayload, 0);
1843  SEND_LOCK(client);
1844  send_err (mp, ECA_ALLOCMEM, client,
1845  "subscription install into record %s failed",
1846  RECORD_NAME(pciu->dbch));
1847  SEND_UNLOCK(client);
1848  return RSRV_ERROR;
1849  }
1850 
1851  /*
1852  * always send it once at event add
1853  */
1854  /*
1855  * if the client program issues many monitors
1856  * in a row then I recv when the send side
1857  * of the socket would block. This prevents
1858  * a application program initiated deadlock.
1859  *
1860  * However when I am reconnecting I reissue
1861  * the monitors and I could get deadlocked.
1862  * The client is blocked sending and the server
1863  * task for the client is blocked sending in
1864  * this case. I cant check the recv part of the
1865  * socket in the client since I am still handling an
1866  * outstanding recv ( they must be processed in order).
1867  * I handle this problem in the server by using
1868  * post_single_event() below instead of calling
1869  * read_reply() in this module. This is a complete
1870  * fix since a monitor setup is the only request
1871  * soliciting a reply in the client which is
1872  * issued from inside of service.c (from inside
1873  * of the part of the ca client which services
1874  * messages sent by the server).
1875  */
1876 
1877  DLOG ( 3, ("event_add_action: db_post_single_event (0x%X)\n",
1878  pevext->pdbev) );
1879  db_post_single_event(pevext->pdbev);
1880 
1881  /*
1882  * enable future labor if we have read access
1883  */
1884  if(asCheckGet(pciu->asClientPVT)){
1885  db_event_enable(pevext->pdbev);
1886  }
1887  else {
1888  DLOG ( 3, ( "Disable event because cannot read\n" ) );
1889  }
1890 
1891  return RSRV_OK;
1892 }
1893 
1894 /*
1895  * clear_channel_reply()
1896  */
1897 static int clear_channel_reply ( caHdrLargeArray *mp,
1898  void *pPayload, struct client *client )
1899 {
1900  struct event_ext *pevext;
1901  struct channel_in_use *pciu;
1902  int status;
1903 
1904  /*
1905  *
1906  * Verify the channel
1907  *
1908  */
1909  pciu = MPTOPCIU(mp);
1910  if(pciu?pciu->client!=client:TRUE){
1911  logBadId ( client, mp, pPayload );
1912  return RSRV_ERROR;
1913  }
1914 
1915  rsrvFreePutNotify ( client, pciu->pPutNotify );
1916 
1917  while (TRUE){
1918  epicsMutexMustLock(client->eventqLock);
1919  pevext = (struct event_ext *) ellGet(&pciu->eventq);
1920  epicsMutexUnlock(client->eventqLock);
1921 
1922  if(!pevext){
1923  break;
1924  }
1925 
1926  if (pevext->pdbev) {
1927  db_cancel_event (pevext->pdbev);
1928  }
1930  }
1931 
1932  db_flush_extra_labor_event ( client->evuser );
1933 
1934  /*
1935  * send delete confirmed message
1936  */
1937  SEND_LOCK(client);
1938  status = cas_copy_in_header ( client, CA_PROTO_CLEAR_CHANNEL,
1939  0u, mp->m_dataType, mp->m_count, mp->m_cid,
1940  mp->m_available, NULL );
1941  if ( status != ECA_NORMAL ) {
1942  SEND_UNLOCK(client);
1943  return RSRV_ERROR;
1944  }
1945 
1946  cas_commit_msg ( client, 0u );
1947  SEND_UNLOCK(client);
1948 
1949  /*
1950  * remove from access control list
1951  */
1952  status = asRemoveClient(&pciu->asClientPVT);
1953  if(status != 0 && status != S_asLib_asNotActive){
1954  errMessage(status, RECORD_NAME(pciu->dbch));
1955  return RSRV_ERROR;
1956  }
1957 
1958  epicsMutexMustLock ( client->chanListLock );
1959  if ( pciu->state == rsrvCS_inService ||
1960  pciu->state == rsrvCS_pendConnectResp ) {
1961  ellDelete ( &client->chanList, &pciu->node );
1962  pciu->state = rsrvCS_shutdown;
1963  }
1964  else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ||
1966  ellDelete ( &client->chanPendingUpdateARList, &pciu->node );
1967  pciu->state = rsrvCS_shutdown;
1968  }
1969  else if ( pciu->state == rsrvCS_shutdown ) {
1970  /* no-op */
1971  }
1972  else {
1973  epicsMutexUnlock( client->chanListLock );
1974  SEND_LOCK(client);
1975  send_err(mp, ECA_INTERNAL, client,
1976  "channel was in strange state or corrupted during cleanup");
1977  SEND_UNLOCK(client);
1978  return RSRV_ERROR;
1979  }
1980  epicsMutexUnlock( client->chanListLock );
1981 
1982  LOCK_CLIENTQ;
1983  status = bucketRemoveItemUnsignedId (pCaBucket, &pciu->sid);
1984  if(status != S_bucket_success){
1986  errMessage (status, "Bad resource id during channel clear");
1987  logBadId ( client, mp, pPayload );
1988  return RSRV_ERROR;
1989  }
1990  rsrvChannelCount--;
1992 
1993  dbChannelDelete(pciu->dbch);
1995 
1996  return RSRV_OK;
1997 }
1998 
1999 /*
2000  *
2001  * event_cancel_reply()
2002  *
2003  *
2004  * Much more efficient now since the event blocks hang off the channel in use
2005  * blocks not all together off the client block.
2006  */
2007 static int event_cancel_reply ( caHdrLargeArray *mp, void *pPayload, struct client *client )
2008 {
2009  struct channel_in_use *pciu;
2010  struct event_ext *pevext;
2011  int status;
2012 
2013  /*
2014  *
2015  * Verify the channel
2016  *
2017  */
2018  pciu = MPTOPCIU(mp);
2019  if (pciu?pciu->client!=client:TRUE) {
2020  logBadId ( client, mp, pPayload );
2021  return RSRV_ERROR;
2022  }
2023 
2024  /*
2025  * search events on this channel for a match
2026  * (there are usually very few monitors per channel)
2027  */
2028  epicsMutexMustLock(client->eventqLock);
2029  for (pevext = (struct event_ext *) ellFirst(&pciu->eventq);
2030  pevext; pevext = (struct event_ext *) ellNext(&pevext->node)){
2031 
2032  if (pevext->msg.m_available == mp->m_available) {
2033  ellDelete(&pciu->eventq, &pevext->node);
2034  break;
2035  }
2036  }
2037  epicsMutexUnlock(client->eventqLock);
2038 
2039  /*
2040  * Not Found- return an exception event
2041  */
2042  if(!pevext){
2043  SEND_LOCK(client);
2044  send_err(mp, ECA_BADMONID, client, RECORD_NAME(pciu->dbch));
2045  SEND_UNLOCK(client);
2046  return RSRV_ERROR;
2047  }
2048 
2049  /*
2050  * cancel monitor activity in progress
2051  */
2052  if (pevext->pdbev) {
2053  db_cancel_event (pevext->pdbev);
2054  }
2055 
2056  /*
2057  * send delete confirmed message
2058  */
2059  SEND_LOCK(client);
2060 
2061  status = cas_copy_in_header ( client, pevext->msg.m_cmmd,
2062  0u, pevext->msg.m_dataType, pevext->msg.m_count, pevext->msg.m_cid,
2063  pevext->msg.m_available, NULL );
2064  if ( status != ECA_NORMAL ) {
2065  SEND_UNLOCK(client);
2066  return RSRV_ERROR;
2067  }
2068  cas_commit_msg ( client, 0 );
2069  SEND_UNLOCK(client);
2070 
2071  freeListFree (rsrvEventFreeList, pevext);
2072 
2073  return RSRV_OK;
2074 }
2075 
2076 /*
2077  * read_sync_reply()
2078  */
2079 static int read_sync_reply ( caHdrLargeArray *mp, void *pPayload, struct client *client )
2080 {
2081  int status;
2082  SEND_LOCK(client);
2083  status = cas_copy_in_header ( client, mp->m_cmmd,
2084  0u, mp->m_dataType, mp->m_count, mp->m_cid,
2085  mp->m_available, NULL );
2086  if ( status != ECA_NORMAL ) {
2087  SEND_UNLOCK(client);
2088  return RSRV_ERROR;
2089  }
2090  cas_commit_msg ( client, 0 );
2091  SEND_UNLOCK(client);
2092  return RSRV_OK;
2093 }
2094 
2095 /*
2096  * search_fail_reply()
2097  *
2098  * Only when requested by the client
2099  * send search failed reply
2100  */
2101 static void search_fail_reply ( caHdrLargeArray *mp, void *pPayload, struct client *client)
2102 {
2103  int status;
2104  SEND_LOCK ( client );
2105  status = cas_copy_in_header ( client, CA_PROTO_NOT_FOUND,
2106  0u, mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available, NULL );
2107  if ( status != ECA_NORMAL ) {
2108  SEND_UNLOCK ( client );
2109  errlogPrintf ( "%s at %d: should always get sufficent space for search fail reply?\n",
2110  __FILE__, __LINE__ );
2111  return;
2112  }
2113  cas_commit_msg ( client, 0 );
2114  SEND_UNLOCK ( client );
2115 }
2116 
2117 /*
2118  * udp_version_action()
2119  */
2120 static int udp_version_action ( caHdrLargeArray *mp, void *pPayload, struct client *client )
2121 {
2122  client->minor_version_number = mp->m_count;
2123 
2124  if (!CA_VSUPPORTED(mp->m_count)) {
2125  DLOG ( 2, ( "CAS: Ignore version from unsupported client %u\n", mp->m_count ) );
2126  return RSRV_ERROR;
2127  }
2128 
2129  if ( CA_V411 ( mp->m_count ) ) {
2130  client->seqNoOfReq = mp->m_cid;
2131  }
2132  else {
2133  client->seqNoOfReq = 0;
2134  }
2135  return RSRV_OK;
2136 }
2137 
2138 /*
2139  * rsrv_version_reply()
2140  */
2141 int rsrv_version_reply ( struct client *client )
2142 {
2143  int status;
2144  SEND_LOCK ( client );
2145  /*
2146  * sequence number is specified zero when we copy in the
2147  * header because we dont know it until we receive a datagram
2148  * from the client
2149  */
2150  status = cas_copy_in_header ( client, CA_PROTO_VERSION,
2152  0, 0, 0 );
2153  if ( status != ECA_NORMAL ) {
2154  SEND_UNLOCK ( client );
2155  return RSRV_ERROR;
2156  }
2157  cas_commit_msg ( client, 0 );
2158  SEND_UNLOCK ( client );
2159  return RSRV_OK;
2160 }
2161 
2162 /*
2163  * search_reply_udp ()
2164  */
2165 static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client *client )
2166 {
2167  ca_uint16_t *pMinorVersion;
2168  char *pName = (char *) pPayload;
2169  int status;
2170  unsigned sid;
2171  ca_uint16_t count;
2172  ca_uint16_t type;
2173  int spaceAvailOnFreeList;
2174  size_t spaceNeeded;
2175  size_t reasonableMonitorSpace = 10;
2176 
2177  if (!CA_VSUPPORTED(mp->m_count)) {
2178  DLOG ( 2, ( "CAS: Ignore search from unsupported client %u\n", mp->m_count ) );
2179  return RSRV_ERROR;
2180  }
2181 
2182  /*
2183  * check the sanity of the message
2184  */
2185  if (mp->m_postsize<=1) {
2186  log_header ("empty PV name in UDP search request?",
2187  client, mp, pPayload, 0);
2188  return RSRV_OK;
2189  }
2190  pName[mp->m_postsize-1] = '\0';
2191 
2192  /* Exit quickly if channel not on this node */
2193  if (dbChannelTest(pName)) {
2194  DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
2195  return RSRV_OK;
2196  }
2197 
2198  /*
2199  * stop further use of server if memory becomes scarce
2200  */
2201  spaceAvailOnFreeList = freeListItemsAvail ( rsrvChanFreeList ) > 0
2202  && freeListItemsAvail ( rsrvEventFreeList ) > reasonableMonitorSpace;
2203  spaceNeeded = sizeof (struct channel_in_use) +
2204  reasonableMonitorSpace * sizeof (struct event_ext);
2205  if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
2206  return RSRV_ERROR;
2207  }
2208 
2209  /*
2210  * starting with V4.4 the count field is used (abused)
2211  * to store the minor version number of the client.
2212  *
2213  * New versions dont alloc the channel in response
2214  * to a search request.
2215  * For these, allocation has been moved to claim_ciu_action().
2216  *
2217  * m_count, m_cid are already in host format...
2218  */
2219  if (CA_V44(mp->m_count)) {
2220  sid = ~0U;
2221  count = 0;
2222  type = ca_server_port;
2223  }
2224  else {
2225  /* shouldn't actually get here due to VSUPPORTED test */
2226  return RSRV_ERROR;
2227  }
2228 
2229  SEND_LOCK ( client );
2230  status = cas_copy_in_header ( client, CA_PROTO_SEARCH,
2231  sizeof(*pMinorVersion), type, count,
2232  sid, mp->m_available,
2233  ( void * ) &pMinorVersion );
2234  if ( status != ECA_NORMAL ) {
2235  SEND_UNLOCK ( client );
2236  return RSRV_ERROR;
2237  }
2238 
2239  /*
2240  * Starting with CA V4.1 the minor version number
2241  * is appended to the end of each search reply.
2242  * This value is ignored by earlier clients.
2243  */
2244  *pMinorVersion = htons ( CA_MINOR_PROTOCOL_REVISION );
2245 
2246  cas_commit_msg ( client, sizeof ( *pMinorVersion ) );
2247  SEND_UNLOCK ( client );
2248 
2249  return RSRV_OK;
2250 }
2251 
2252 /*
2253  * search_reply_tcp ()
2254  */
2255 static int search_reply_tcp (
2256  caHdrLargeArray *mp, void *pPayload, struct client *client )
2257 {
2258  char *pName = (char *) pPayload;
2259  int status;
2260  int spaceAvailOnFreeList;
2261  size_t spaceNeeded;
2262  size_t reasonableMonitorSpace = 10;
2263 
2264  if (!CA_VSUPPORTED(mp->m_count)) {
2265  DLOG ( 2, ( "CAS: Ignore search from unsupported client %u\n", mp->m_count ) );
2266  return RSRV_ERROR;
2267  }
2268 
2269  /*
2270  * check the sanity of the message
2271  */
2272  if (mp->m_postsize<=1) {
2273  log_header ("empty PV name in UDP search request?",
2274  client, mp, pPayload, 0);
2275  return RSRV_OK;
2276  }
2277  pName[mp->m_postsize-1] = '\0';
2278 
2279  /* Exit quickly if channel not on this node */
2280  if (dbChannelTest(pName)) {
2281  DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
2282  if (mp->m_dataType == DOREPLY)
2283  search_fail_reply ( mp, pPayload, client );
2284  return RSRV_OK;
2285  }
2286 
2287  /*
2288  * stop further use of server if memory becomes scarse
2289  */
2290  spaceAvailOnFreeList = freeListItemsAvail ( rsrvChanFreeList ) > 0
2291  && freeListItemsAvail ( rsrvEventFreeList ) > reasonableMonitorSpace;
2292  spaceNeeded = sizeof (struct channel_in_use) +
2293  reasonableMonitorSpace * sizeof (struct event_ext);
2294  if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
2295  SEND_LOCK(client);
2296  send_err ( mp, ECA_ALLOCMEM, client, "Server memory exhausted" );
2297  SEND_UNLOCK(client);
2298  return RSRV_OK;
2299  }
2300 
2301  SEND_LOCK ( client );
2302  status = cas_copy_in_header ( client, CA_PROTO_SEARCH,
2303  0, ca_server_port, 0, ~0U, mp->m_available, 0 );
2304  if ( status != ECA_NORMAL ) {
2305  SEND_UNLOCK ( client );
2306  return RSRV_ERROR;
2307  }
2308 
2309  cas_commit_msg ( client, 0 );
2310  SEND_UNLOCK ( client );
2311 
2312  return RSRV_OK;
2313 }
2314 
2315 typedef int (*pProtoStubTCP) (caHdrLargeArray *mp, void *pPayload, struct client *client);
2316 
2317 /*
2318  * TCP protocol jump table
2319  */
2320 static const pProtoStubTCP tcpJumpTable[] =
2321 {
2322  tcp_version_action,
2323  event_add_action,
2324  event_cancel_reply,
2325  read_action,
2326  write_action,
2327  bad_tcp_cmd_action,
2328  search_reply_tcp,
2329  bad_tcp_cmd_action,
2330  events_off_action,
2331  events_on_action,
2332  read_sync_reply,
2333  bad_tcp_cmd_action,
2334  clear_channel_reply,
2335  bad_tcp_cmd_action,
2336  bad_tcp_cmd_action,
2337  read_notify_action,
2338  bad_tcp_cmd_action,
2339  bad_tcp_cmd_action,
2340  claim_ciu_action,
2341  write_notify_action,
2342  client_name_action,
2343  host_name_action,
2344  bad_tcp_cmd_action,
2345  tcp_echo_action,
2346  bad_tcp_cmd_action,
2347  bad_tcp_cmd_action,
2348  bad_tcp_cmd_action,
2349  bad_tcp_cmd_action
2350 };
2351 
2352 /*
2353  * UDP protocol jump table
2354  */
2355 typedef int (*pProtoStubUDP) (caHdrLargeArray *mp, void *pPayload, struct client *client);
2356 static const pProtoStubUDP udpJumpTable[] =
2357 {
2358  udp_version_action,
2359  bad_udp_cmd_action,
2360  bad_udp_cmd_action,
2361  bad_udp_cmd_action,
2362  bad_udp_cmd_action,
2363  bad_udp_cmd_action,
2364  search_reply_udp,
2365  bad_udp_cmd_action,
2366  bad_udp_cmd_action,
2367  bad_udp_cmd_action,
2368  bad_udp_cmd_action,
2369  bad_udp_cmd_action,
2370  bad_udp_cmd_action,
2371  bad_udp_cmd_action,
2372  bad_udp_cmd_action,
2373  bad_udp_cmd_action,
2374  bad_udp_cmd_action,
2375  bad_udp_cmd_action,
2376  bad_udp_cmd_action,
2377  bad_udp_cmd_action,
2378  bad_udp_cmd_action,
2379  bad_udp_cmd_action,
2380  bad_udp_cmd_action,
2381  bad_udp_cmd_action,
2382  bad_udp_cmd_action,
2383  bad_udp_cmd_action,
2384  bad_udp_cmd_action,
2385  bad_udp_cmd_action
2386 };
2387 
2388 /*
2389  * CAMESSAGE()
2390  */
2391 int camessage ( struct client *client )
2392 {
2393  unsigned nmsg = 0;
2394  unsigned msgsize;
2395  unsigned bytes_left;
2396  int status = RSRV_ERROR;
2397 
2398  assert(pCaBucket);
2399 
2400  /* drain remnents of large messages that will not fit */
2401  if ( client->recvBytesToDrain ) {
2402  if ( client->recvBytesToDrain >= client->recv.cnt ) {
2403  client->recvBytesToDrain -= client->recv.cnt;
2404  client->recv.stk = client->recv.cnt;
2405  return RSRV_OK;
2406  }
2407  else {
2408  client->recv.stk += client->recvBytesToDrain;
2409  client->recvBytesToDrain = 0u;
2410  }
2411  }
2412 
2413  DLOG ( 2, ( "CAS: Parsing %d(decimal) bytes\n", recv->cnt ) );
2414 
2415  while ( 1 )
2416  {
2418  caHdr *mp;
2419  void *pBody;
2420 
2421  /* wait for at least a complete caHdr */
2422  bytes_left = client->recv.cnt - client->recv.stk;
2423  if ( bytes_left < sizeof(*mp) ) {
2424  status = RSRV_OK;
2425  break;
2426  }
2427 
2428  mp = (caHdr *) &client->recv.buf[client->recv.stk];
2429  msg.m_cmmd = ntohs ( mp->m_cmmd );
2430  msg.m_postsize = ntohs ( mp->m_postsize );
2431  msg.m_dataType = ntohs ( mp->m_dataType );
2432  msg.m_count = ntohs ( mp->m_count );
2433  msg.m_cid = ntohl ( mp->m_cid );
2434  msg.m_available = ntohl ( mp->m_available );
2435 
2436  if ( CA_V49(client->minor_version_number) && msg.m_postsize == 0xffff ) {
2437  ca_uint32_t *pLW = ( ca_uint32_t * ) ( mp + 1 );
2438  if ( bytes_left < sizeof(*mp) + 2 * sizeof(*pLW) ) {
2439  status = RSRV_OK;
2440  break;
2441  }
2442  msg.m_postsize = ntohl ( pLW[0] );
2443  msg.m_count = ntohl ( pLW[1] );
2444  msgsize = msg.m_postsize + sizeof(*mp) + 2 * sizeof ( *pLW );
2445  pBody = ( void * ) ( pLW + 2 );
2446  }
2447  else {
2448  msgsize = msg.m_postsize + sizeof(*mp);
2449  pBody = ( void * ) ( mp + 1 );
2450  }
2451 
2452  /* ignore deprecated clients, but let newer clients identify themselves. */
2454  if (client->proto==IPPROTO_TCP) {
2455  /* log and error for too old clients, but keep the connection open to avoid a
2456  * re-connect loop.
2457  */
2458  SEND_LOCK(client);
2459  send_err ( &msg, ECA_DEFUNCT, client,
2460  "CAS: Client version %u too old", client->minor_version_number );
2461  SEND_UNLOCK(client);
2462  log_header ( "CAS: Client version too old",
2463  client, &msg, 0, nmsg );
2464  client->recvBytesToDrain = msgsize - bytes_left;
2465  client->recv.stk = client->recv.cnt;
2466  status = RSRV_OK;
2467  } else {
2468  /* silently ignore UDP from old clients */
2469  status = RSRV_ERROR;
2470  }
2471  break;
2472  }
2473 
2474  /*
2475  * disconnect clients that dont send 8 byte
2476  * aligned payloads
2477  */
2478  if ( msgsize & 0x7 ) {
2479  if (client->proto==IPPROTO_TCP) {
2480  SEND_LOCK(client);
2481  send_err ( &msg, ECA_INTERNAL, client,
2482  "CAS: Missaligned protocol rejected" );
2483  SEND_UNLOCK(client);
2484  log_header ( "CAS: Missaligned protocol rejected",
2485  client, &msg, 0, nmsg );
2486  }
2487  status = RSRV_ERROR;
2488  break;
2489  }
2490 
2491  /* problem: we have a complete header,
2492  * but before we check msgsize we don't know
2493  * if we have a complete message body
2494  * -> we may be called again with the same header
2495  * after receiving the full message
2496  */
2497  if ( msgsize > client->recv.maxstk ) {
2498  casExpandRecvBuffer ( client, msgsize );
2499  if ( msgsize > client->recv.maxstk ) {
2500  if (client->proto==IPPROTO_TCP) {
2501  SEND_LOCK(client);
2502  send_err ( &msg, ECA_TOLARGE, client,
2503  "CAS: Server unable to load large request message. Max bytes=%lu",
2505  SEND_UNLOCK(client);
2506  log_header ( "CAS: server unable to load large request message",
2507  client, &msg, 0, nmsg );
2508  }
2509  assert ( client->recv.cnt <= client->recv.maxstk );
2510  assert ( msgsize >= bytes_left );
2511  client->recvBytesToDrain = msgsize - bytes_left;
2512  client->recv.stk = client->recv.cnt;
2513  status = RSRV_OK;
2514  break;
2515  }
2516  }
2517 
2518  /*
2519  * wait for complete message body
2520  */
2521  if ( msgsize > bytes_left ) {
2522  status = RSRV_OK;
2523  break;
2524  }
2525 
2526  nmsg++;
2527 
2528  if ( CASDEBUG > 2 )
2529  log_header (NULL, client, &msg, pBody, nmsg);
2530 
2531  if ( client->proto==IPPROTO_UDP ) {
2532  if ( msg.m_cmmd < NELEMENTS ( udpJumpTable ) ) {
2533  status = ( *udpJumpTable[msg.m_cmmd] )( &msg, pBody, client );
2534  if (status!=RSRV_OK) {
2535  status = RSRV_ERROR;
2536  break;
2537  }
2538  }
2539  else {
2540  status = bad_udp_cmd_action ( &msg, pBody, client );
2541  break;
2542  }
2543  }
2544  else {
2545  if ( msg.m_cmmd < NELEMENTS(tcpJumpTable) ) {
2546  status = ( *tcpJumpTable[msg.m_cmmd] ) ( &msg, pBody, client );
2547  if ( status != RSRV_OK ) {
2548  status = RSRV_ERROR;
2549  break;
2550  }
2551  }
2552  else {
2553  return bad_tcp_cmd_action ( &msg, pBody, client );
2554  }
2555  }
2556 
2557  client->recv.stk += msgsize;
2558  }
2559 
2560  return status;
2561 }
2562 
2563 /*
2564  * rsrvCheckPut ()
2565  */
2566 int rsrvCheckPut (const struct channel_in_use *pciu)
2567 {
2568  /*
2569  * SPC_NOMOD fields are always unwritable
2570  */
2571  if (dbChannelSpecial(pciu->dbch) == SPC_NOMOD) {
2572  return 0;
2573  }
2574  else {
2575  return asCheckPut (pciu->asClientPVT);
2576  }
2577 }
#define ECA_PUTCBINPROG
Definition: caerr.h:122
struct dbChannel * dbch
Definition: server.h:139
epicsTimeStamp time_at_creation
Definition: server.h:138
dbr_long_t longval
Definition: camessage.c:83
GLBLTYPE int CASDEBUG
Definition: server.h:190
LIBCOM_API void *epicsStdCall freeListCalloc(void *pvt)
Definition: freeListLib.c:60
#define DBR_STRING
Definition: db_access.h:69
void rsrvFreePutNotify(client *pClient, struct rsrv_put_notify *pNotify)
Definition: camessage.c:1616
struct message_buffer recv
Definition: server.h:81
#define LAST_BUFFER_TYPE
Definition: db_access.h:113
int rsrv_version_reply(struct client *client)
Definition: camessage.c:2141
int(* pProtoStubUDP)(caHdrLargeArray *mp, void *pPayload, struct client *client)
Definition: camessage.c:2355
#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
#define CA_PROTO_CREATE_CHAN
Definition: caProto.h:101
LIBCOM_API int asCheckClientIP
Definition: asLibRoutines.c:31
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
unsigned cnt
Definition: server.h:70
struct client client
#define CA_PROTO_EVENT_ADD
Definition: caProto.h:84
processNotify dbPutNotify
Definition: camessage.c:66
pvd::Status status
unsigned size
Definition: server.h:153
struct rsrv_put_notify RSRVPUTNOTIFY
#define asCheckPut(asClientPvt)
Definition: asLib.h:45
const unsigned sid
Definition: server.h:137
unsigned maxstk
Definition: server.h:68
#define CA_PROTO_VERSION
Definition: caProto.h:83
char * pUserName
Definition: server.h:93
#define ECA_INTERNAL
Definition: caerr.h:94
#define asCheckGet(asClientPvt)
Definition: asLib.h:43
int lineno
Definition: antelope.c:33
#define CA_V411(MINOR)
Definition: caProto.h:42
int rsrvCheckPut(const struct channel_in_use *pciu)
Definition: camessage.c:2566
#define CA_PROTO_WRITE
Definition: caProto.h:87
LIBCOM_API void *epicsStdCall bucketLookupItemUnsignedId(BUCKET *prb, const unsigned *pId)
Find an item identified by an unsigned int in the table.
Definition: bucketLib.c:435
LIBCOM_API int epicsStdCall LIBCOM_API int epicsStdCall epicsVsnprintf(char *str, size_t size, const char *format, va_list ap)
Definition: osdStdio.c:26
#define logBadId(CLIENT, MP, PPL)
Definition: camessage.c:58
struct rsrv_put_notify * pPutNotify
Definition: server.h:135
ca_uint32_t m_postsize
#define ECA_GETFAIL
Definition: caerr.h:96
#define DOREPLY
Definition: caProto.h:118
#define CA_PROTO_WRITE_NOTIFY
Definition: caProto.h:102
int caNetConvert(unsigned type, const void *pSrc, void *pDest, int hton, arrayElementCount count)
Definition: convert.cpp:1420
int errlogVprintf(const char *pFormat, va_list pvar)
Definition: errlog.c:144
#define SPC_NOMOD
Definition: special.h:26
ca_uint32_t m_available
Definition: caProto.h:166
#define CA_PROTO_EVENT_CANCEL
Definition: caProto.h:85
LOCAL int write_notify_put_callback(processNotify *ppn, notifyPutType type)
Definition: camessage.c:1324
epicsFloat32 dbr_float_t
Definition: db_access.h:46
#define ECA_PUTFAIL
Definition: caerr.h:97
LIBCOM_API long epicsStdCall asAddClient(ASCLIENTPVT *asClientPvt, ASMEMBERPVT asMemberPvt, int asl, const char *user, char *host)
dbr_char_t charval
Definition: camessage.c:82
void casExpandRecvBuffer(struct client *pClient, ca_uint32_t size)
LIBCOM_API long epicsStdCall asRegisterClientCallback(ASCLIENTPVT asClientPvt, ASCLIENTCALLBACK pcallback)
pvd::StructureConstPtr type
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
#define asTrapWriteWithData(asClientPvt, user, host, addr, type, count, data)
Definition: asLib.h:54
#define INVALID_DB_REQ(x)
Definition: db_access.h:115
#define CA_PROTO_READ
Definition: caProto.h:86
epicsEventId blockSem
Definition: server.h:95
LIBCOM_API void epicsStdCall asPutClientPvt(ASCLIENTPVT asClientPvt, void *userPvt)
void * pbuffer
Definition: camessage.c:87
#define NULL
Definition: catime.c:38
#define errMessage(S, PM)
Definition: errlog.h:48
ca_uint16_t m_dataType
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout(epicsEventId id, double timeOut)
Wait an the event or until the specified timeout period is over.
Definition: osdEvent.c:117
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
#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
dbr_double_t doubleval
Definition: camessage.c:84
#define asTrapWriteAfter(pvt)
Definition: asLib.h:58
enum rsrvChanState state
Definition: server.h:141
void initializePutNotifyFreeList(void)
Definition: camessage.c:1530
#define CA_PROTO_EVENTS_OFF
Definition: caProto.h:91
LIBCOM_API int epicsStdCall bucketAddItemUnsignedId(BUCKET *prb, const unsigned *pId, const void *pApp)
Add an item identified by an unsigned int to the table.
Definition: bucketLib.c:308
const unsigned cid
Definition: server.h:136
unsigned short ca_uint16_t
Definition: caProto.h:75
unsigned stk
Definition: server.h:67
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
int proto
Definition: server.h:97
ELLLIST putNotifyQue
Definition: server.h:88
#define CA_V44(MINOR)
Definition: caProto.h:35
#define CA_V49(MINOR)
Definition: caProto.h:40
struct sockaddr_in addr
Definition: server.h:89
#define CA_PROTO_READ_SYNC
Definition: caProto.h:93
#define CA_MINOR_PROTOCOL_REVISION
Definition: nciu.h:35
dbr_float_t fltval
Definition: camessage.c:80
#define CA_PROTO_ACCESS_RIGHT_READ
Definition: caProto.h:143
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
asClientStatus
Definition: asLib.h:32
ca_uint16_t m_cmmd
Definition: caProto.h:161
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
dbr_enum_t enmval
Definition: camessage.c:81
caHdrLargeArray msg
Definition: server.h:150
ca_uint32_t m_count
#define SEND_UNLOCK(CLIENT)
Definition: server.h:221
epicsMutexId chanListLock
Definition: server.h:84
#define ECA_NORMAL
Definition: caerr.h:77
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
char onExtraLaborQueue
Definition: camessage.c:94
#define ECA_TOLARGE
Definition: caerr.h:86
Definition: server.h:76
#define CA_PROTO_SNAPSHOT
Definition: caProto.h:88
dbr_short_t shrtval
Definition: camessage.c:78
#define CA_PROTO_ERROR
Definition: caProto.h:94
LOCAL void write_notify_done_callback(processNotify *ppn)
Definition: camessage.c:1346
APIs for the epicsMutex mutual exclusion semaphore.
struct client * client
Definition: server.h:134
unsigned recvBytesToDrain
Definition: server.h:101
#define RECORD_NAME(CHAN)
Definition: camessage.c:54
LIBCOM_API void epicsStdCall freeListFree(void *pvt, void *pmem)
Definition: freeListLib.c:131
ca_uint32_t m_cid
Definition: caProto.h:165
int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
Get current time into *pDest.
#define CA_PROTO_PRIORITY_MIN
Definition: caProto.h:66
#define RSRV_OK
Definition: rsrv.h:23
#define epicsPrintf
Definition: errlog.h:51
LIBCOM_API size_t epicsStdCall freeListItemsAvail(void *pvt)
Definition: freeListLib.c:171
char * buf
Definition: server.h:65
#define ECA_BADMONID
Definition: caerr.h:107
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 camessage(struct client *client)
Definition: camessage.c:2391
#define CA_PROTO_SEARCH
Definition: caProto.h:89
epicsFloat64 dbr_double_t
Definition: db_access.h:47
ca_uint16_t m_postsize
Definition: caProto.h:162
ASCLIENTPVT asClientPVT
Definition: server.h:140
caHdrLargeArray msg
Definition: camessage.c:67
LIBCOM_API long epicsStdCall asRemoveClient(ASCLIENTPVT *asClientPvt)
LIBCOM_API void *epicsStdCall asGetClientPvt(ASCLIENTPVT asClientPvt)
GLBLTYPE BUCKET * pCaBucket
Definition: server.h:199
ca_uint16_t m_dataType
Definition: caProto.h:163
epicsOldString dbr_string_t
Definition: db_access.h:38
#define NELEMENTS(A)
Definition: aToIPAddr.c:21
epicsMutexId eventqLock
Definition: server.h:85
#define CA_PROTO_NOT_FOUND
Definition: caProto.h:97
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
List node type.
Definition: ellLib.h:45
epicsUInt8 dbr_char_t
Definition: db_access.h:39
#define ECA_NOWTACCESS
Definition: caerr.h:124
struct ca_hdr caHdr
ca_uint16_t m_count
Definition: caProto.h:164
#define CA_PROTO_CLEAR_CHANNEL
Definition: caProto.h:95
int cas_copy_in_header(struct client *pclient, ca_uint16_t response, ca_uint32_t payloadSize, ca_uint16_t dataType, ca_uint32_t nElem, ca_uint32_t cid, ca_uint32_t responseSpecific, void **ppPayload)
Definition: caserverio.c:251
APIs for the epicsEvent binary semaphore.
GLBLTYPE void * rsrvChanFreeList
Definition: server.h:201
unsigned mask
Definition: server.h:154
GLBLTYPE unsigned rsrvSizeofLargeBufTCP
Definition: server.h:205
union rsrv_put_notify::@1 dbrScalarValue
ca_uint32_t m_cid
GLBLTYPE void * rsrvEventFreeList
Definition: server.h:202
#define epicsThreadPriorityCAServerHigh
Definition: epicsThread.h:81
LIBCOM_API epicsThreadBooleanStatus epicsStdCall epicsThreadHighestPriorityLevelBelow(unsigned int priority, unsigned *pPriorityJustBelow)
Definition: osdThread.c:740
#define CA_PROTO_CREATE_CH_FAIL
Definition: caProto.h:109
LIBCOM_API unsigned int epicsStdCall epicsThreadGetPrioritySelf(void)
Definition: osdThread.c:707
epicsUInt16 dbr_enum_t
Definition: db_access.h:43
#define epicsThreadPriorityCAServerLow
Definition: epicsThread.h:80
const char *epicsStdCall ca_message(long ca_status)
Definition: access.cpp:561
#define CA_PROTO_READ_NOTIFY
Definition: caProto.h:98
size_t epicsStrnLen(const char *s, size_t maxlen)
Definition: epicsString.c:268
#define CA_PROTO_ACCESS_RIGHT_WRITE
Definition: caProto.h:144
#define LOCAL
Deprecated synonym for static.
Definition: dbDefs.h:36
#define RSRV_ERROR
Definition: rsrv.h:24
ELLNODE node
Definition: server.h:149
ELLLIST chanPendingUpdateARList
Definition: server.h:87
ELLLIST eventq
Definition: server.h:133
void cas_set_header_cid(struct client *pClient, ca_uint32_t cid)
Definition: caserverio.c:329
ELLNODE node
Definition: camessage.c:65
void cas_commit_msg(struct client *pClient, ca_uint32_t size)
Definition: caserverio.c:351
#define DLOG(LEVEL, ARGSINPAREN)
Definition: server.h:187
ELLNODE node
Definition: server.h:132
void * asDbGetMemberPvt(struct dbChannel *chan)
Definition: asDbLib.c:218
#define CA_VSUPPORTED(MINOR)
Definition: caProto.h:31
#define dbr_size_n(TYPE, COUNT)
Definition: db_access.h:518
void * asWritePvt
Definition: camessage.c:91
#define TRUE
Definition: dbDefs.h:27
#define ECA_NORDACCESS
Definition: caerr.h:123
int(* pProtoStubTCP)(caHdrLargeArray *mp, void *pPayload, struct client *client)
Definition: camessage.c:2315
int asDbGetAsl(struct dbChannel *chan)
Definition: asDbLib.c:213
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
#define epicsEventWaitOK
Old name provided for backwards compatibility.
Definition: epicsEvent.h:58
GLBLTYPE unsigned short ca_server_port
Definition: server.h:191
ca_uint16_t m_cmmd
#define S_bucket_idInUse
Identifier already in use.
Definition: bucketLib.h:187
struct channel_in_use * pciu
Definition: server.h:151
ca_uint32_t m_available
void * evuser
Definition: server.h:92
#define ECA_BADTYPE
Definition: caerr.h:91
unsigned valueSize
Definition: camessage.c:92
unsigned minor_version_number
Definition: server.h:99
#define CA_PROTO_ACCESS_RIGHTS
Definition: caProto.h:105
#define UNLOCK_CLIENTQ
Definition: server.h:224
#define CA_PROTO_EVENTS_ON
Definition: caProto.h:92
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
epicsInt16 dbr_short_t
Definition: db_access.h:40
epicsInt32 dbr_long_t
Definition: db_access.h:44
C++ and C descriptions for a thread.
#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
ELLNODE node
Pointers to the first and last nodes on list.
Definition: ellLib.h:57
dbr_short_t intval
Definition: camessage.c:79
#define S_bucket_success
Success, must be 0.
Definition: bucketLib.h:179
GLBLTYPE unsigned rsrvChannelCount
Definition: server.h:207
ca_uint32_t seqNoOfReq
Definition: server.h:100
unsigned priority
Definition: server.h:102
void cas_send_bs_msg(struct client *pclient, int lock_needed)
Definition: caserverio.c:44
dbr_string_t strval
Definition: camessage.c:77
#define S_asLib_asNotActive
Definition: asLib.h:137
void cas_set_header_count(struct client *pClient, ca_uint32_t count)
Definition: caserverio.c:335
unsigned rsrvSizeOfPutNotify(struct rsrv_put_notify *pNotify)
Definition: camessage.c:1604
LIBCOM_API void epicsStdCall epicsThreadSetPriority(epicsThreadId id, unsigned int priority)
Definition: osdThread.c:713
GLBLTYPE void * rsrvPutNotifyFreeList
Definition: server.h:206
#define ECA_DEFUNCT
Definition: caerr.h:111
#define ECA_ALLOCMEM
Definition: caerr.h:83
#define SEND_LOCK(CLIENT)
Definition: server.h:220
#define CA_PROTO_PRIORITY_MAX
Definition: caProto.h:67
unsigned epicsStdCall ipAddrToDottedIP(const struct sockaddr_in *paddr, char *pBuf, unsigned bufSize)
Definition: osiSock.c:144
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
ca_uint16_t m_mask
Definition: caProto.h:176
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810