PageRenderTime 29ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/ATF2/control-software/epics-3.14.8/base/src/cas/generic/casDGClient.cc

http://atf2flightsim.googlecode.com/
C++ | 956 lines | 614 code | 112 blank | 230 comment | 91 complexity | 74353bd0a98485b605230670ae4dd18d MD5 | raw file
Possible License(s): BSD-2-Clause, LGPL-2.0, IPL-1.0, BSD-3-Clause
  1. /*************************************************************************\
  2. * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
  3. * National Laboratory.
  4. * Copyright (c) 2002 The Regents of the University of California, as
  5. * Operator of Los Alamos National Laboratory.
  6. * EPICS BASE Versions 3.13.7
  7. * and higher are distributed subject to a Software License Agreement found
  8. * in file LICENSE that is included with this distribution.
  9. \*************************************************************************/
  10. /*
  11. * casDGClient.cc,v 1.50.2.8 2009/07/30 23:29:43 jhill Exp
  12. *
  13. * Author Jeffrey O. Hill
  14. * johill@lanl.gov
  15. * 505 665 1831
  16. */
  17. #include "gddApps.h"
  18. #include "caerr.h"
  19. #include "osiWireFormat.h"
  20. #include "errlog.h"
  21. #define epicsExportSharedSymbols
  22. #include "casDGClient.h"
  23. #include "osiPoolStatus.h" // osi pool monitoring functions
  24. casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
  25. {
  26. & casDGClient::versionAction,
  27. & casDGClient::uknownMessageAction,
  28. & casDGClient::uknownMessageAction,
  29. & casDGClient::uknownMessageAction,
  30. & casDGClient::uknownMessageAction,
  31. & casDGClient::uknownMessageAction,
  32. & casDGClient::searchAction,
  33. & casDGClient::uknownMessageAction,
  34. & casDGClient::uknownMessageAction,
  35. & casDGClient::uknownMessageAction,
  36. & casDGClient::uknownMessageAction,
  37. & casDGClient::uknownMessageAction,
  38. & casDGClient::uknownMessageAction,
  39. & casDGClient::uknownMessageAction,
  40. & casDGClient::uknownMessageAction,
  41. & casDGClient::uknownMessageAction,
  42. & casDGClient::uknownMessageAction,
  43. & casDGClient::uknownMessageAction,
  44. & casDGClient::uknownMessageAction,
  45. & casDGClient::uknownMessageAction,
  46. & casDGClient::uknownMessageAction,
  47. & casDGClient::uknownMessageAction,
  48. & casDGClient::uknownMessageAction,
  49. & casDGClient::echoAction,
  50. & casDGClient::uknownMessageAction,
  51. & casDGClient::uknownMessageAction,
  52. & casDGClient::uknownMessageAction,
  53. & casDGClient::uknownMessageAction
  54. };
  55. //
  56. // casDGClient::casDGClient()
  57. //
  58. casDGClient::casDGClient ( caServerI & serverIn, clientBufMemoryManager & mgrIn ) :
  59. casCoreClient ( serverIn ),
  60. in ( *this, mgrIn, MAX_UDP_RECV + sizeof ( cadg ) ),
  61. out ( *this, mgrIn ),
  62. seqNoOfReq ( 0 ),
  63. minor_version_number ( 0 )
  64. {
  65. }
  66. //
  67. // casDGClient::~casDGClient()
  68. // (virtual destructor)
  69. //
  70. casDGClient::~casDGClient()
  71. {
  72. }
  73. //
  74. // casDGClient::destroy()
  75. //
  76. void casDGClient::destroy()
  77. {
  78. printf("Attempt to destroy the DG client was ignored\n");
  79. }
  80. //
  81. // casDGClient::show()
  82. //
  83. void casDGClient::show (unsigned level) const
  84. {
  85. printf ( "casDGClient at %p\n",
  86. static_cast <const void *> ( this ) );
  87. if (level>=1u) {
  88. char buf[64];
  89. this->hostName (buf, sizeof(buf));
  90. printf ("Client Host=%s\n", buf);
  91. this->casCoreClient::show ( level - 1u );
  92. this->in.show ( level - 1u );
  93. this->out.show ( level - 1u );
  94. }
  95. }
  96. //
  97. // casDGClient::uknownMessageAction()
  98. //
  99. caStatus casDGClient::uknownMessageAction ()
  100. {
  101. const caHdrLargeArray * mp = this->ctx.getMsg();
  102. char pHostName[64u];
  103. this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
  104. caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
  105. "bad request code=%u in DG\n", mp->m_cmmd );
  106. return S_cas_badProtocol;
  107. }
  108. //
  109. // casDGClient::searchAction()
  110. //
  111. caStatus casDGClient::searchAction()
  112. {
  113. const caHdrLargeArray *mp = this->ctx.getMsg();
  114. const char *pChanName = static_cast <char * > ( this->ctx.getData() );
  115. caStatus status;
  116. //
  117. // check the sanity of the message
  118. //
  119. if ( mp->m_postsize <= 1 ) {
  120. char pHostName[64u];
  121. this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
  122. caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
  123. "empty PV name extension in UDP search request?\n" );
  124. return S_cas_success;
  125. }
  126. if ( pChanName[0] == '\0' ) {
  127. char pHostName[64u];
  128. this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
  129. caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
  130. "zero length PV name in UDP search request?\n" );
  131. return S_cas_success;
  132. }
  133. // check for an unterminated string before calling server tool
  134. // by searching backwards through the string (some early versions
  135. // of the client library might not be setting the pad bytes to nill)
  136. for ( unsigned i = mp->m_postsize-1; pChanName[i] != '\0'; i-- ) {
  137. if ( i <= 1 ) {
  138. char pHostName[64u];
  139. this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
  140. caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
  141. "unterminated PV name in UDP search request?\n" );
  142. return S_cas_success;
  143. }
  144. }
  145. if ( this->getCAS().getDebugLevel() > 6u ) {
  146. char pHostName[64u];
  147. this->hostName ( pHostName, sizeof ( pHostName ) );
  148. printf ( "\"%s\" is searching for \"%s\"\n",
  149. pHostName, pChanName );
  150. }
  151. //
  152. // verify that we have sufficent memory for a PV and a
  153. // monitor prior to calling PV exist test so that when
  154. // the server runs out of memory we dont reply to
  155. // search requests, and therefore dont thrash through
  156. // caServer::pvExistTest() and casCreatePV::pvAttach()
  157. //
  158. if ( ! osiSufficentSpaceInPool ( 0 ) ) {
  159. return S_cas_success;
  160. }
  161. //
  162. // ask the server tool if this PV exists
  163. //
  164. this->userStartedAsyncIO = false;
  165. pvExistReturn pver =
  166. this->getCAS()->pvExistTest ( this->ctx, this->lastRecvAddr, pChanName );
  167. //
  168. // prevent problems when they initiate
  169. // async IO but dont return status
  170. // indicating so (and vise versa)
  171. //
  172. if ( this->userStartedAsyncIO ) {
  173. if ( pver.getStatus() != pverAsyncCompletion ) {
  174. errMessage (S_cas_badParameter,
  175. "- assuming asynch IO status from caServer::pvExistTest()");
  176. }
  177. status = S_cas_success;
  178. }
  179. else {
  180. //
  181. // otherwise we assume sync IO operation was initiated
  182. //
  183. switch ( pver.getStatus() ) {
  184. case pverExistsHere:
  185. status = this->searchResponse (*mp, pver);
  186. break;
  187. case pverDoesNotExistHere:
  188. status = S_cas_success;
  189. break;
  190. case pverAsyncCompletion:
  191. errMessage (S_cas_badParameter,
  192. "- unexpected asynch IO status from caServer::pvExistTest() ignored");
  193. status = S_cas_success;
  194. break;
  195. default:
  196. errMessage (S_cas_badParameter,
  197. "- invalid return from caServer::pvExistTest() ignored");
  198. status = S_cas_success;
  199. break;
  200. }
  201. }
  202. return status;
  203. }
  204. //
  205. // caStatus casDGClient::searchResponse()
  206. //
  207. caStatus casDGClient::searchResponse ( const caHdrLargeArray & msg,
  208. const pvExistReturn & retVal )
  209. {
  210. caStatus status;
  211. if ( retVal.getStatus() != pverExistsHere ) {
  212. return S_cas_success;
  213. }
  214. //
  215. // starting with V4.1 the count field is used (abused)
  216. // by the client to store the minor version number of
  217. // the client.
  218. //
  219. // Old versions expect alloc of channel in response
  220. // to a search request. This is no longer supported.
  221. //
  222. if ( !CA_V44(msg.m_count) ) {
  223. char pName[64u];
  224. this->hostName (pName, sizeof (pName));
  225. errlogPrintf (
  226. "client \"%s\" using EPICS R3.11 CA connect protocol was ignored\n",
  227. pName);
  228. //
  229. // old connect protocol was dropped when the
  230. // new API was added to the server (they must
  231. // now use clients at EPICS 3.12 or higher)
  232. //
  233. status = this->sendErr ( &msg, ECA_DEFUNCT, invalidResID,
  234. "R3.11 connect sequence from old client was ignored" );
  235. return status;
  236. }
  237. //
  238. // cid field is abused to carry the IP
  239. // address in CA_V48 or higher
  240. // (this allows a CA servers to serve
  241. // as a directory service)
  242. //
  243. // data type field is abused to carry the IP
  244. // port number here CA_V44 or higher
  245. // (this allows multiple CA servers on one
  246. // host)
  247. //
  248. ca_uint32_t serverAddr;
  249. ca_uint16_t serverPort;
  250. if ( CA_V48( msg.m_count ) ) {
  251. struct sockaddr_in ina;
  252. if ( retVal.addrIsValid() ) {
  253. caNetAddr addr = retVal.getAddr();
  254. ina = addr.getSockIP();
  255. //
  256. // If they dont specify a port number then the default
  257. // CA server port is assumed when it it is a server
  258. // address redirect (it is never correct to use this
  259. // server's port when it is a redirect).
  260. //
  261. if (ina.sin_port==0u) {
  262. ina.sin_port = htons ( CA_SERVER_PORT );
  263. }
  264. }
  265. else {
  266. caNetAddr addr = this->serverAddress ();
  267. ina = addr.getSockIP();
  268. //
  269. // We dont fill in the servers address here
  270. // because the server was not bound to a particular
  271. // interface, and we would need to waste CPU performing
  272. // the following steps to determine the interface that
  273. // will be used:
  274. //
  275. // o connect UDP socket to the destination IP
  276. // o perform a getsockname() call
  277. // o disconnect UDP socket from the destination IP
  278. //
  279. if ( ina.sin_addr.s_addr == INADDR_ANY ) {
  280. ina.sin_addr.s_addr = htonl ( ~0U );
  281. }
  282. }
  283. serverAddr = ntohl ( ina.sin_addr.s_addr );
  284. serverPort = ntohs ( ina.sin_port );
  285. }
  286. else {
  287. caNetAddr addr = this->serverAddress ();
  288. struct sockaddr_in inetAddr = addr.getSockIP();
  289. serverAddr = ~0U;
  290. serverPort = ntohs ( inetAddr.sin_port );
  291. }
  292. ca_uint16_t * pMinorVersion;
  293. epicsGuard < epicsMutex > guard ( this->mutex );
  294. status = this->out.copyInHeader ( CA_PROTO_SEARCH,
  295. sizeof ( *pMinorVersion ), serverPort, 0,
  296. serverAddr, msg.m_available,
  297. reinterpret_cast <void **> ( &pMinorVersion ) );
  298. //
  299. // Starting with CA V4.1 the minor version number
  300. // is appended to the end of each search reply.
  301. // This value is ignored by earlier clients.
  302. //
  303. if ( status == S_cas_success ) {
  304. AlignedWireRef < epicsUInt16 > tmp ( *pMinorVersion );
  305. tmp = CA_MINOR_PROTOCOL_REVISION;
  306. this->out.commitMsg ();
  307. }
  308. return status;
  309. }
  310. //
  311. // casDGClient::searchFailResponse()
  312. // (only when requested by the client
  313. // - when it isnt a reply to a broadcast)
  314. //
  315. caStatus casDGClient::searchFailResponse ( const caHdrLargeArray * mp )
  316. {
  317. int status;
  318. epicsGuard < epicsMutex > guard ( this->mutex );
  319. status = this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
  320. mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available, 0 );
  321. this->out.commitMsg ();
  322. return S_cas_success;
  323. }
  324. /*
  325. * casDGClient::versionAction()
  326. */
  327. caStatus casDGClient::versionAction ()
  328. {
  329. const caHdrLargeArray * mp = this->ctx.getMsg();
  330. if ( mp->m_count != 0 ) {
  331. this->minor_version_number = static_cast <ca_uint16_t> ( mp->m_count );
  332. if ( CA_V411 ( mp->m_count ) ) {
  333. this->seqNoOfReq = mp->m_cid;
  334. }
  335. else {
  336. this->seqNoOfReq = 0;
  337. }
  338. }
  339. return S_cas_success;
  340. }
  341. //
  342. // casDGClient::sendBeacon()
  343. // (implemented here because this has knowledge of the protocol)
  344. //
  345. void casDGClient::sendBeacon ( ca_uint32_t beaconNumber )
  346. {
  347. union {
  348. caHdr msg;
  349. char buf;
  350. };
  351. //
  352. // create the message
  353. //
  354. memset ( & buf, 0, sizeof ( msg ) );
  355. AlignedWireRef < epicsUInt16 > ( msg.m_cmmd ) = CA_PROTO_RSRV_IS_UP;
  356. AlignedWireRef < epicsUInt16 > ( msg.m_dataType ) = CA_MINOR_PROTOCOL_REVISION;
  357. AlignedWireRef < epicsUInt32 > ( msg.m_cid ) = beaconNumber;
  358. //
  359. // send it to all addresses on the beacon list,
  360. // but let the IO specific code set the address
  361. // field and the port field
  362. //
  363. this->sendBeaconIO ( buf, sizeof (msg), msg.m_count, msg.m_available );
  364. }
  365. //
  366. // casDGClient::xSend()
  367. //
  368. outBufClient::flushCondition casDGClient::xSend ( char *pBufIn,
  369. bufSizeT nBytesToSend, bufSizeT & nBytesSent )
  370. {
  371. bufSizeT totalBytes = 0;
  372. while ( totalBytes < nBytesToSend ) {
  373. cadg *pHdr = reinterpret_cast < cadg * > ( & pBufIn[totalBytes] );
  374. assert ( totalBytes <= bufSizeT_MAX - pHdr->cadg_nBytes );
  375. assert ( totalBytes + pHdr->cadg_nBytes <= nBytesToSend );
  376. char * pDG = reinterpret_cast < char * > ( pHdr + 1 );
  377. unsigned sizeDG = pHdr->cadg_nBytes - sizeof ( *pHdr );
  378. if ( pHdr->cadg_addr.isValid() ) {
  379. outBufClient::flushCondition stat =
  380. this->osdSend ( pDG, sizeDG, pHdr->cadg_addr );
  381. if ( stat != outBufClient::flushProgress ) {
  382. break;
  383. }
  384. }
  385. totalBytes += pHdr->cadg_nBytes;
  386. }
  387. if ( totalBytes ) {
  388. //
  389. // !! this time fetch may be slowing things down !!
  390. //
  391. //this->lastSendTS = epicsTime::getCurrent();
  392. nBytesSent = totalBytes;
  393. return outBufClient::flushProgress;
  394. }
  395. else {
  396. return outBufClient::flushNone;
  397. }
  398. }
  399. //
  400. // casDGClient::xRecv ()
  401. //
  402. inBufClient::fillCondition casDGClient::xRecv (char *pBufIn, bufSizeT nBytesToRecv, // X aCC 361
  403. fillParameter parm, bufSizeT &nByesRecv)
  404. {
  405. const char *pAfter = pBufIn + nBytesToRecv;
  406. char *pCurBuf = pBufIn;
  407. bufSizeT nDGBytesRecv;
  408. inBufClient::fillCondition stat;
  409. cadg *pHdr;
  410. while (pAfter-pCurBuf >= static_cast<int>(MAX_UDP_RECV+sizeof(cadg))) {
  411. pHdr = reinterpret_cast < cadg * > ( pCurBuf );
  412. stat = this->osdRecv ( reinterpret_cast < char * > ( pHdr + 1 ),
  413. MAX_UDP_RECV, parm, nDGBytesRecv, pHdr->cadg_addr);
  414. if (stat==casFillProgress) {
  415. pHdr->cadg_nBytes = nDGBytesRecv + sizeof(*pHdr);
  416. pCurBuf += pHdr->cadg_nBytes;
  417. //
  418. // !! this time fetch may be slowing things down !!
  419. //
  420. //this->lastRecvTS = epicsTime::getCurrent();
  421. }
  422. else {
  423. break;
  424. }
  425. }
  426. nDGBytesRecv = pCurBuf - pBufIn;
  427. if (nDGBytesRecv) {
  428. nByesRecv = nDGBytesRecv;
  429. return casFillProgress;
  430. }
  431. else {
  432. return casFillNone;
  433. }
  434. }
  435. //
  436. // casDGClient::asyncSearchResp()
  437. //
  438. //
  439. // this results in many small UDP frames which unfortunately
  440. // isnt particularly efficient
  441. //
  442. caStatus casDGClient::asyncSearchResponse (
  443. epicsGuard < casClientMutex > &, const caNetAddr & outAddr,
  444. const caHdrLargeArray & msg, const pvExistReturn & retVal,
  445. ca_uint16_t protocolRevision, ca_uint32_t sequenceNumber )
  446. {
  447. if ( retVal.getStatus() != pverExistsHere ) {
  448. return S_cas_success;
  449. }
  450. void * pRaw;
  451. const outBufCtx outctx = this->out.pushCtx
  452. ( sizeof(cadg), MAX_UDP_SEND, pRaw );
  453. if ( outctx.pushResult() != outBufCtx::pushCtxSuccess ) {
  454. return S_cas_sendBlocked;
  455. }
  456. cadg * pRespHdr = static_cast < cadg * > ( pRaw );
  457. // insert version header at the start of the reply message
  458. this->sendVersion ();
  459. caHdr * pMsg = reinterpret_cast < caHdr * > ( pRespHdr + 1 );
  460. assert ( ntohs ( pMsg->m_cmmd ) == CA_PROTO_VERSION );
  461. if ( CA_V411 ( protocolRevision ) ) {
  462. pMsg->m_cid = htonl ( sequenceNumber );
  463. pMsg->m_dataType = htons ( sequenceNoIsValid );
  464. }
  465. caStatus stat = this->searchResponse ( msg, retVal );
  466. pRespHdr->cadg_nBytes = this->out.popCtx (outctx) + sizeof ( *pRespHdr );
  467. if ( pRespHdr->cadg_nBytes > sizeof ( *pRespHdr ) + sizeof (caHdr) ) {
  468. pRespHdr->cadg_addr = outAddr;
  469. this->out.commitRawMsg ( pRespHdr->cadg_nBytes );
  470. }
  471. return stat;
  472. }
  473. //
  474. // casDGClient::processDG ()
  475. //
  476. caStatus casDGClient::processDG ()
  477. {
  478. bufSizeT bytesLeft;
  479. caStatus status;
  480. status = S_cas_success;
  481. while ( ( bytesLeft = this->in.bytesPresent() ) ) {
  482. bufSizeT dgInBytesConsumed;
  483. const cadg * pReqHdr = reinterpret_cast < cadg * > ( this->in.msgPtr () );
  484. if (bytesLeft<sizeof(*pReqHdr)) {
  485. this->in.removeMsg (bytesLeft);
  486. errlogPrintf ("casDGClient::processMsg: incomplete DG header?");
  487. status = S_cas_internal;
  488. break;
  489. }
  490. epicsGuard < epicsMutex > guard ( this->mutex );
  491. //
  492. // start a DG context in the output protocol stream
  493. // and grab the send lock
  494. //
  495. void *pRaw;
  496. const outBufCtx outctx = this->out.pushCtx ( sizeof ( cadg ), MAX_UDP_SEND, pRaw );
  497. if ( outctx.pushResult() != outBufCtx::pushCtxSuccess ) {
  498. status = S_cas_sendBlocked;
  499. break;
  500. }
  501. // insert version header at the start of the reply message
  502. this->sendVersion ();
  503. cadg * pRespHdr = static_cast < cadg * > ( pRaw );
  504. //
  505. // select the next DG in the input stream and start processing it
  506. //
  507. const bufSizeT reqBodySize = pReqHdr->cadg_nBytes - sizeof (*pReqHdr);
  508. const inBufCtx inctx = this->in.pushCtx ( sizeof (*pReqHdr), reqBodySize);
  509. if ( inctx.pushResult() != inBufCtx::pushCtxSuccess ) {
  510. this->in.removeMsg ( bytesLeft );
  511. this->out.popCtx ( outctx );
  512. errlogPrintf ("casDGClient::processMsg: incomplete DG?\n");
  513. status = S_cas_internal;
  514. break;
  515. }
  516. this->lastRecvAddr = pReqHdr->cadg_addr;
  517. this->seqNoOfReq = 0;
  518. this->minor_version_number = 0;
  519. status = this->processMsg ();
  520. pRespHdr->cadg_nBytes = this->out.popCtx ( outctx ) + sizeof ( *pRespHdr );
  521. dgInBytesConsumed = this->in.popCtx ( inctx );
  522. if ( dgInBytesConsumed > 0 ) {
  523. //
  524. // at this point processMsg() bailed out because:
  525. // a) it used all of the incoming DG or
  526. // b) it used all of the outgoing DG
  527. //
  528. // In either case commit the DG to the protocol stream and
  529. // release the send lock
  530. //
  531. // if there are not additional messages passed the version header
  532. // then discard the message
  533. if ( pRespHdr->cadg_nBytes > sizeof ( *pRespHdr ) + sizeof (caHdr) ) {
  534. pRespHdr->cadg_addr = pReqHdr->cadg_addr;
  535. caHdr * pMsg = reinterpret_cast < caHdr * > ( pRespHdr + 1 );
  536. assert ( ntohs ( pMsg->m_cmmd ) == CA_PROTO_VERSION );
  537. if ( CA_V411 ( this->minor_version_number ) ) {
  538. pMsg->m_cid = htonl ( this->seqNoOfReq );
  539. pMsg->m_dataType = htons ( sequenceNoIsValid );
  540. }
  541. this->out.commitRawMsg ( pRespHdr->cadg_nBytes );
  542. }
  543. //
  544. // check to see that all of the incoming UDP frame was used
  545. //
  546. if ( dgInBytesConsumed < reqBodySize ) {
  547. //
  548. // remove the bytes in the body that were consumed,
  549. // but _not_ the header bytes
  550. //
  551. this->in.removeMsg (dgInBytesConsumed);
  552. //
  553. // slide the UDP header forward and correct the byte count
  554. //
  555. {
  556. cadg *pReqHdrMove;
  557. cadg copy = *pReqHdr;
  558. pReqHdrMove = reinterpret_cast < cadg * > ( this->in.msgPtr () );
  559. pReqHdrMove->cadg_addr = copy.cadg_addr;
  560. pReqHdrMove->cadg_nBytes = copy.cadg_nBytes - dgInBytesConsumed;
  561. }
  562. }
  563. else {
  564. //
  565. // remove the header and all of the body
  566. //
  567. this->in.removeMsg ( pReqHdr->cadg_nBytes );
  568. }
  569. }
  570. if ( status != S_cas_success ) {
  571. break;
  572. }
  573. }
  574. return status;
  575. }
  576. //
  577. // casDGClient::getDebugLevel()
  578. //
  579. unsigned casDGClient::getDebugLevel() const
  580. {
  581. return this->getCAS().getDebugLevel();
  582. }
  583. //
  584. // casDGClient::fetchLastRecvAddr ()
  585. //
  586. caNetAddr casDGClient::fetchLastRecvAddr () const
  587. {
  588. return this->lastRecvAddr;
  589. }
  590. //
  591. // casDGClient::datagramSequenceNumber ()
  592. //
  593. ca_uint32_t casDGClient::datagramSequenceNumber () const
  594. {
  595. return this->seqNoOfReq;
  596. }
  597. //
  598. // casDGClient::hostName()
  599. //
  600. void casDGClient::hostName ( char *pBufIn, unsigned bufSizeIn ) const
  601. {
  602. this->lastRecvAddr.stringConvert ( pBufIn, bufSizeIn );
  603. }
  604. // send minor protocol revision to the client
  605. void casDGClient::sendVersion ()
  606. {
  607. epicsGuard < epicsMutex > guard ( this->mutex );
  608. caStatus status = this->out.copyInHeader ( CA_PROTO_VERSION, 0,
  609. 0, CA_MINOR_PROTOCOL_REVISION, 0, 0, 0 );
  610. if ( ! status ) {
  611. this->out.commitMsg ();
  612. }
  613. }
  614. bool casDGClient::inBufFull () const
  615. {
  616. epicsGuard < epicsMutex > guard ( this->mutex );
  617. return this->in.full ();
  618. }
  619. void casDGClient::inBufFill ( inBufClient::fillParameter parm )
  620. {
  621. epicsGuard < epicsMutex > guard ( this->mutex );
  622. this->in.fill ( parm );
  623. }
  624. bufSizeT casDGClient ::
  625. inBufBytesPending () const
  626. {
  627. epicsGuard < epicsMutex > guard ( this->mutex );
  628. return this->in.bytesPresent ();
  629. }
  630. bufSizeT casDGClient ::
  631. outBufBytesPending () const
  632. {
  633. epicsGuard < epicsMutex > guard ( this->mutex );
  634. return this->out.bytesPresent ();
  635. }
  636. outBufClient::flushCondition casDGClient::flush ()
  637. {
  638. epicsGuard < epicsMutex > guard ( this->mutex );
  639. return this->out.flush ();
  640. }
  641. //
  642. // casDGClient::processMsg ()
  643. // process any messages in the in buffer
  644. //
  645. caStatus casDGClient::processMsg ()
  646. {
  647. int status = S_cas_success;
  648. try {
  649. unsigned bytesLeft;
  650. while ( ( bytesLeft = this->in.bytesPresent() ) ) {
  651. caHdrLargeArray msgTmp;
  652. unsigned msgSize;
  653. ca_uint32_t hdrSize;
  654. char * rawMP;
  655. {
  656. //
  657. // copy as raw bytes in order to avoid
  658. // alignment problems
  659. //
  660. caHdr smallHdr;
  661. if ( bytesLeft < sizeof ( smallHdr ) ) {
  662. break;
  663. }
  664. rawMP = this->in.msgPtr ();
  665. memcpy ( & smallHdr, rawMP, sizeof ( smallHdr ) );
  666. ca_uint32_t payloadSize = AlignedWireRef < epicsUInt16 > ( smallHdr.m_postsize );
  667. ca_uint32_t nElem = AlignedWireRef < epicsUInt16 > ( smallHdr.m_count );
  668. if ( payloadSize != 0xffff && nElem != 0xffff ) {
  669. hdrSize = sizeof ( smallHdr );
  670. }
  671. else {
  672. ca_uint32_t LWA[2];
  673. hdrSize = sizeof ( smallHdr ) + sizeof ( LWA );
  674. if ( bytesLeft < hdrSize ) {
  675. break;
  676. }
  677. //
  678. // copy as raw bytes in order to avoid
  679. // alignment problems
  680. //
  681. memcpy ( LWA, rawMP + sizeof ( caHdr ), sizeof( LWA ) );
  682. payloadSize = AlignedWireRef < epicsUInt32 > ( LWA[0] );
  683. nElem = AlignedWireRef < epicsUInt32 > ( LWA[1] );
  684. }
  685. msgTmp.m_cmmd = AlignedWireRef < epicsUInt16 > ( smallHdr.m_cmmd );
  686. msgTmp.m_postsize = payloadSize;
  687. msgTmp.m_dataType = AlignedWireRef < epicsUInt16 > ( smallHdr.m_dataType );
  688. msgTmp.m_count = nElem;
  689. msgTmp.m_cid = AlignedWireRef < epicsUInt32 > ( smallHdr.m_cid );
  690. msgTmp.m_available = AlignedWireRef < epicsUInt32 > ( smallHdr.m_available );
  691. if ( payloadSize & 0x7 ) {
  692. status = this->sendErr (
  693. & msgTmp, invalidResID, ECA_INTERNAL,
  694. "CAS: Datagram request wasn't 8 byte aligned" );
  695. this->in.removeMsg ( bytesLeft );
  696. break;
  697. }
  698. msgSize = hdrSize + payloadSize;
  699. if ( bytesLeft < msgSize ) {
  700. if ( msgSize > this->in.bufferSize() ) {
  701. status = this->sendErr ( & msgTmp, invalidResID, ECA_TOLARGE,
  702. "client's request didnt fit within the CA server's message buffer" );
  703. this->in.removeMsg ( bytesLeft );
  704. }
  705. break;
  706. }
  707. this->ctx.setMsg ( msgTmp, rawMP + hdrSize );
  708. if ( this->getCAS().getDebugLevel() > 5u ) {
  709. char pHostName[64u];
  710. this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
  711. caServerI::dumpMsg ( pHostName, "?",
  712. & msgTmp, rawMP + hdrSize, 0 );
  713. }
  714. }
  715. //
  716. // Reset the context to the default
  717. // (guarantees that previous message does not get mixed
  718. // up with the current message)
  719. //
  720. this->ctx.setChannel ( NULL );
  721. this->ctx.setPV ( NULL );
  722. //
  723. // Call protocol stub
  724. //
  725. casDGClient::pCASMsgHandler pHandler;
  726. if ( msgTmp.m_cmmd < NELEMENTS ( casDGClient::msgHandlers ) ) {
  727. pHandler = this->casDGClient::msgHandlers[msgTmp.m_cmmd];
  728. }
  729. else {
  730. pHandler = & casDGClient::uknownMessageAction;
  731. }
  732. status = ( this->*pHandler ) ();
  733. if ( status ) {
  734. this->in.removeMsg ( this->in.bytesPresent() );
  735. break;
  736. }
  737. this->in.removeMsg ( msgSize );
  738. }
  739. }
  740. catch ( std::exception & except ) {
  741. this->in.removeMsg ( this->in.bytesPresent() );
  742. status = this->sendErr (
  743. this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
  744. "C++ exception \"%s\" in CA circuit server",
  745. except.what () );
  746. status = S_cas_internal;
  747. }
  748. catch (...) {
  749. this->in.removeMsg ( this->in.bytesPresent() );
  750. status = this->sendErr (
  751. this->ctx.getMsg(), invalidResID, ECA_INTERNAL,
  752. "unexpected C++ exception in CA datagram server" );
  753. status = S_cas_internal;
  754. }
  755. return status;
  756. }
  757. //
  758. // casDGClient::sendErr()
  759. //
  760. caStatus casDGClient::sendErr ( const caHdrLargeArray *curp,
  761. ca_uint32_t cid, const int reportedStatus, const char *pformat, ... )
  762. {
  763. unsigned stringSize;
  764. char msgBuf[1024]; /* allocate plenty of space for the message string */
  765. if ( pformat ) {
  766. va_list args;
  767. va_start ( args, pformat );
  768. int status = vsprintf ( msgBuf, pformat, args );
  769. if ( status < 0 ) {
  770. errPrintf (S_cas_internal, __FILE__, __LINE__,
  771. "bad sendErr(%s)", pformat);
  772. stringSize = 0u;
  773. }
  774. else {
  775. stringSize = 1u + (unsigned) status;
  776. }
  777. }
  778. else {
  779. stringSize = 0u;
  780. }
  781. unsigned hdrSize = sizeof ( caHdr );
  782. if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
  783. CA_V49( this->minor_version_number ) ) {
  784. hdrSize += 2 * sizeof ( ca_uint32_t );
  785. }
  786. caHdr * pReqOut;
  787. epicsGuard < epicsMutex > guard ( this->mutex );
  788. caStatus status = this->out.copyInHeader ( CA_PROTO_ERROR,
  789. hdrSize + stringSize, 0, 0, cid, reportedStatus,
  790. reinterpret_cast <void **> ( & pReqOut ) );
  791. if ( ! status ) {
  792. char * pMsgString;
  793. /*
  794. * copy back the request protocol
  795. * (in network byte order)
  796. */
  797. if ( ( curp->m_postsize >= 0xffff || curp->m_count >= 0xffff ) &&
  798. CA_V49( this->minor_version_number ) ) {
  799. ca_uint32_t *pLW = ( ca_uint32_t * ) ( pReqOut + 1 );
  800. pReqOut->m_cmmd = htons ( curp->m_cmmd );
  801. pReqOut->m_postsize = htons ( 0xffff );
  802. pReqOut->m_dataType = htons ( curp->m_dataType );
  803. pReqOut->m_count = htons ( 0u );
  804. pReqOut->m_cid = htonl ( curp->m_cid );
  805. pReqOut->m_available = htonl ( curp->m_available );
  806. pLW[0] = htonl ( curp->m_postsize );
  807. pLW[1] = htonl ( curp->m_count );
  808. pMsgString = ( char * ) ( pLW + 2 );
  809. }
  810. else {
  811. pReqOut->m_cmmd = htons (curp->m_cmmd);
  812. pReqOut->m_postsize = htons ( ( (ca_uint16_t) curp->m_postsize ) );
  813. pReqOut->m_dataType = htons (curp->m_dataType);
  814. pReqOut->m_count = htons ( ( (ca_uint16_t) curp->m_count ) );
  815. pReqOut->m_cid = htonl (curp->m_cid);
  816. pReqOut->m_available = htonl (curp->m_available);
  817. pMsgString = ( char * ) ( pReqOut + 1 );
  818. }
  819. /*
  820. * add their context string into the protocol
  821. */
  822. memcpy ( pMsgString, msgBuf, stringSize );
  823. this->out.commitMsg ();
  824. }
  825. return S_cas_success;
  826. }
  827. //
  828. // echoAction()
  829. //
  830. caStatus casDGClient::echoAction ()
  831. {
  832. const caHdrLargeArray * mp = this->ctx.getMsg();
  833. const void * dp = this->ctx.getData();
  834. void * pPayloadOut;
  835. epicsGuard < epicsMutex > guard ( this->mutex );
  836. caStatus status = this->out.copyInHeader ( mp->m_cmmd, mp->m_postsize,
  837. mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
  838. & pPayloadOut );
  839. if ( ! status ) {
  840. memcpy ( pPayloadOut, dp, mp->m_postsize );
  841. this->out.commitMsg ();
  842. }
  843. return S_cas_success;
  844. }