This is Unofficial EPICS BASE Doxygen Site
camessage.c File Reference
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <limits.h>
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "epicsTime.h"
#include "errlog.h"
#include "freeList.h"
#include "osiPoolStatus.h"
#include "osiSock.h"
#include "caerr.h"
#include "net_convert.h"
#include "asDbLib.h"
#include "callback.h"
#include "db_access.h"
#include "db_access_routines.h"
#include "dbChannel.h"
#include "dbCommon.h"
#include "dbEvent.h"
#include "db_field_log.h"
#include "dbNotify.h"
#include "rsrv.h"
#include "server.h"
#include "special.h"
+ Include dependency graph for camessage.c:

Go to the source code of this file.

Classes

struct  rsrv_put_notify
 

Macros

#define epicsExportSharedSymbols
 
#define RECORD_NAME(CHAN)   (dbChannelRecord(CHAN)->name)
 
#define logBadId(CLIENT, MP, PPL)   logBadIdWithFileAndLineno(CLIENT, MP, PPL, __FILE__, __LINE__)
 

Typedefs

typedef struct rsrv_put_notify RSRVPUTNOTIFY
 
typedef int(* pProtoStubTCP) (caHdrLargeArray *mp, void *pPayload, struct client *client)
 
typedef int(* pProtoStubUDP) (caHdrLargeArray *mp, void *pPayload, struct client *client)
 

Functions

LOCAL int write_notify_put_callback (processNotify *ppn, notifyPutType type)
 
LOCAL void write_notify_done_callback (processNotify *ppn)
 
void rsrv_extra_labor (void *pArg)
 
void initializePutNotifyFreeList (void)
 
unsigned rsrvSizeOfPutNotify (struct rsrv_put_notify *pNotify)
 
void rsrvFreePutNotify (client *pClient, struct rsrv_put_notify *pNotify)
 
int rsrv_version_reply (struct client *client)
 
int camessage (struct client *client)
 
int rsrvCheckPut (const struct channel_in_use *pciu)
 

Macro Definition Documentation

#define epicsExportSharedSymbols

Definition at line 40 of file camessage.c.

#define logBadId (   CLIENT,
  MP,
  PPL 
)    logBadIdWithFileAndLineno(CLIENT, MP, PPL, __FILE__, __LINE__)

Definition at line 58 of file camessage.c.

#define RECORD_NAME (   CHAN)    (dbChannelRecord(CHAN)->name)

Definition at line 54 of file camessage.c.

Typedef Documentation

typedef int(* pProtoStubTCP) (caHdrLargeArray *mp, void *pPayload, struct client *client)

Definition at line 2315 of file camessage.c.

typedef int(* pProtoStubUDP) (caHdrLargeArray *mp, void *pPayload, struct client *client)

Definition at line 2355 of file camessage.c.

Function Documentation

int camessage ( struct client client)

Definition at line 2391 of file camessage.c.

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  {
2417  caHdrLargeArray msg;
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 }
GLBLTYPE int CASDEBUG
Definition: server.h:190
struct message_buffer recv
Definition: server.h:81
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
unsigned cnt
Definition: server.h:70
pvd::Status status
unsigned maxstk
Definition: server.h:68
#define CA_PROTO_VERSION
Definition: caProto.h:83
#define ECA_INTERNAL
Definition: caerr.h:94
ca_uint32_t m_postsize
ca_uint32_t m_available
Definition: caProto.h:166
void casExpandRecvBuffer(struct client *pClient, ca_uint32_t size)
unsigned int ca_uint32_t
Definition: caProto.h:76
#define NULL
Definition: catime.c:38
ca_uint16_t m_dataType
unsigned stk
Definition: server.h:67
int proto
Definition: server.h:97
#define CA_V49(MINOR)
Definition: caProto.h:40
ca_uint16_t m_cmmd
Definition: caProto.h:161
ca_uint32_t m_count
#define SEND_UNLOCK(CLIENT)
Definition: server.h:221
#define ECA_TOLARGE
Definition: caerr.h:86
unsigned recvBytesToDrain
Definition: server.h:101
ca_uint32_t m_cid
Definition: caProto.h:165
#define RSRV_OK
Definition: rsrv.h:23
char * buf
Definition: server.h:65
ca_uint16_t m_postsize
Definition: caProto.h:162
GLBLTYPE BUCKET * pCaBucket
Definition: server.h:199
ca_uint16_t m_dataType
Definition: caProto.h:163
#define NELEMENTS(A)
Definition: aToIPAddr.c:21
ca_uint16_t m_count
Definition: caProto.h:164
GLBLTYPE unsigned rsrvSizeofLargeBufTCP
Definition: server.h:205
ca_uint32_t m_cid
#define RSRV_ERROR
Definition: rsrv.h:24
#define DLOG(LEVEL, ARGSINPAREN)
Definition: server.h:187
#define CA_VSUPPORTED(MINOR)
Definition: caProto.h:31
ca_uint16_t m_cmmd
ca_uint32_t m_available
unsigned minor_version_number
Definition: server.h:99
#define ECA_DEFUNCT
Definition: caerr.h:111
#define SEND_LOCK(CLIENT)
Definition: server.h:220
void initializePutNotifyFreeList ( void  )

Definition at line 1530 of file camessage.c.

1531 {
1532  if ( ! rsrvPutNotifyFreeList ) {
1534  sizeof(struct rsrv_put_notify), 512 );
1536  }
1537 }
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
LIBCOM_API void epicsStdCall freeListInitPvt(void **ppvt, int size, int nmalloc)
Definition: freeListLib.c:44
GLBLTYPE void * rsrvPutNotifyFreeList
Definition: server.h:206
void rsrv_extra_labor ( void *  pArg)

Definition at line 1497 of file camessage.c.

1498 {
1499  struct client * pClient = pArg;
1500  write_notify_reply ( pClient );
1501  sendAllUpdateAS ( pClient );
1502  cas_send_bs_msg ( pClient, TRUE );
1503 }
Definition: server.h:76
#define TRUE
Definition: dbDefs.h:27
void cas_send_bs_msg(struct client *pclient, int lock_needed)
Definition: caserverio.c:44
int rsrv_version_reply ( struct client client)

Definition at line 2141 of file camessage.c.

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 }
pvd::Status status
#define CA_PROTO_VERSION
Definition: caProto.h:83
#define CA_MINOR_PROTOCOL_REVISION
Definition: nciu.h:35
#define SEND_UNLOCK(CLIENT)
Definition: server.h:221
#define ECA_NORMAL
Definition: caerr.h:77
#define RSRV_OK
Definition: rsrv.h:23
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
#define RSRV_ERROR
Definition: rsrv.h:24
void cas_commit_msg(struct client *pClient, ca_uint32_t size)
Definition: caserverio.c:351
#define SEND_LOCK(CLIENT)
Definition: server.h:220
int rsrvCheckPut ( const struct channel_in_use pciu)

Definition at line 2566 of file camessage.c.

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 }
struct dbChannel * dbch
Definition: server.h:139
#define asCheckPut(asClientPvt)
Definition: asLib.h:45
#define SPC_NOMOD
Definition: special.h:26
ASCLIENTPVT asClientPVT
Definition: server.h:140
void rsrvFreePutNotify ( client pClient,
struct rsrv_put_notify pNotify 
)

Definition at line 1616 of file camessage.c.

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 }
processNotify dbPutNotify
Definition: camessage.c:66
void * pbuffer
Definition: camessage.c:87
#define asTrapWriteAfter(pvt)
Definition: asLib.h:58
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
ELLLIST putNotifyQue
Definition: server.h:88
char onExtraLaborQueue
Definition: camessage.c:94
LIBCOM_API void epicsStdCall freeListFree(void *pvt, void *pmem)
Definition: freeListLib.c:131
union rsrv_put_notify::@1 dbrScalarValue
ELLNODE node
Definition: camessage.c:65
void * asWritePvt
Definition: camessage.c:91
unsigned valueSize
Definition: camessage.c:92
epicsMutexId putNotifyLock
Definition: server.h:83
#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
GLBLTYPE void * rsrvPutNotifyFreeList
Definition: server.h:206
unsigned rsrvSizeOfPutNotify ( struct rsrv_put_notify pNotify)

Definition at line 1604 of file camessage.c.

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 }
union rsrv_put_notify::@1 dbrScalarValue
unsigned valueSize
Definition: camessage.c:92
LOCAL void write_notify_done_callback ( processNotify *  ppn)

Definition at line 1346 of file camessage.c.

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;
1360  epicsMutexMustLock(pClient->putNotifyLock);
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 }
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
struct rsrv_put_notify * pPutNotify
Definition: server.h:135
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
char onExtraLaborQueue
Definition: camessage.c:94
Definition: server.h:76
struct client * client
Definition: server.h:134
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
ELLNODE node
Definition: camessage.c:65
#define TRUE
Definition: dbDefs.h:27
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
LOCAL int write_notify_put_callback ( processNotify *  ppn,
notifyPutType  type 
)

Definition at line 1324 of file camessage.c.

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  }
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
struct rsrv_put_notify * pPutNotify
Definition: server.h:135
pvd::StructureConstPtr type