Merge remote-tracking branch 'camodern/master'
* camodern/master: cas: ignore CA client version older than v4.4 rsrv: remove !CA_V44() code rsrv: no ca exception response to UDP rsrv: ignore CA client version older than v4.4 cas: honor DOREPLY for TCP searches cas: ignore echo and unexpected UDP rsrv: send channel create failure rsrv: UDP search ignore DOREPLY rsrv: ignore echo and unexpected UDP Conflicts: src/ca/legacy/pcas/generic/casDGClient.cc
This commit is contained in:
@@ -28,7 +28,8 @@
|
||||
#define CA_VERSION_STRING( MINOR_REVISION ) \
|
||||
( capStrOfX ( CA_MAJOR_PROTOCOL_REVISION ) "." capStrOfX ( MINOR_REVISION ) )
|
||||
#define CA_UKN_MINOR_VERSION 0u /* unknown minor version */
|
||||
#if CA_MAJOR_PROTOCOL_REVISION == 4u
|
||||
#define CA_MINIMUM_SUPPORTED_VERSION 4u
|
||||
# define CA_VSUPPORTED(MINOR) ((MINOR)>=CA_MINIMUM_SUPPORTED_VERSION)
|
||||
# define CA_V41(MINOR) ((MINOR)>=1u)
|
||||
# define CA_V42(MINOR) ((MINOR)>=2u)
|
||||
# define CA_V43(MINOR) ((MINOR)>=3u)
|
||||
@@ -42,35 +43,6 @@
|
||||
# define CA_V411(MINOR) ((MINOR)>=11u) /* sequence numbers in UDP version command */
|
||||
# define CA_V412(MINOR) ((MINOR)>=12u) /* TCP-based search requests */
|
||||
# define CA_V413(MINOR) ((MINOR)>=13u) /* Allow zero length in requests. */
|
||||
#elif CA_MAJOR_PROTOCOL_REVISION > 4u
|
||||
# define CA_V41(MINOR) ( 1u )
|
||||
# define CA_V42(MINOR) ( 1u )
|
||||
# define CA_V43(MINOR) ( 1u )
|
||||
# define CA_V44(MINOR) ( 1u )
|
||||
# define CA_V45(MINOR) ( 1u )
|
||||
# define CA_V46(MINOR) ( 1u )
|
||||
# define CA_V47(MINOR) ( 1u )
|
||||
# define CA_V48(MINOR) ( 1u )
|
||||
# define CA_V49(MINOR) ( 1u )
|
||||
# define CA_V410(MINOR) ( 1u )
|
||||
# define CA_V411(MINOR) ( 1u )
|
||||
# define CA_V412(MINOR) ( 1u )
|
||||
# define CA_V413(MINOR) ( 1u )
|
||||
#else
|
||||
# define CA_V41(MINOR) ( 0u )
|
||||
# define CA_V42(MINOR) ( 0u )
|
||||
# define CA_V43(MINOR) ( 0u )
|
||||
# define CA_V44(MINOR) ( 0u )
|
||||
# define CA_V45(MINOR) ( 0u )
|
||||
# define CA_V46(MINOR) ( 0u )
|
||||
# define CA_V47(MINOR) ( 0u )
|
||||
# define CA_V48(MINOR) ( 0u )
|
||||
# define CA_V49(MINOR) ( 0u )
|
||||
# define CA_V410(MINOR) ( 0u )
|
||||
# define CA_V411(MINOR) ( 0u )
|
||||
# define CA_V412(MINOR) ( 0u )
|
||||
# define CA_V413(MINOR) ( 0u )
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These port numbers are only used if the CA repeater and
|
||||
|
||||
@@ -51,7 +51,7 @@ casDGClient::pCASMsgHandler const casDGClient::msgHandlers[] =
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::echoAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
& casDGClient::uknownMessageAction,
|
||||
|
||||
& casDGClient::uknownMessageAction,
|
||||
@@ -111,11 +111,13 @@ caStatus casDGClient::uknownMessageAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->lastRecvAddr.stringConvert ( pHostName, sizeof ( pHostName ) );
|
||||
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"bad request code=%u in DG\n", mp->m_cmmd );
|
||||
caServerI::dumpMsg ( pHostName, "?", mp, this->ctx.getData(),
|
||||
"bad request code=%u in DG\n", mp->m_cmmd );
|
||||
}
|
||||
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
@@ -129,6 +131,16 @@ caStatus casDGClient::searchAction()
|
||||
const char *pChanName = static_cast <char * > ( this->ctx.getData() );
|
||||
caStatus status;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\" but is too old\n",
|
||||
pHostName, pChanName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
//
|
||||
// check the sanity of the message
|
||||
//
|
||||
@@ -362,6 +374,15 @@ caStatus casDGClient::versionAction ()
|
||||
{
|
||||
const caHdrLargeArray * mp = this->ctx.getMsg();
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is too old\n",
|
||||
pHostName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
if ( mp->m_count != 0 ) {
|
||||
this->minor_version_number = static_cast <ca_uint16_t> ( mp->m_count );
|
||||
if ( CA_V411 ( mp->m_count ) ) {
|
||||
|
||||
@@ -338,6 +338,16 @@ caStatus casStrmClient::versionAction ( epicsGuard < casClientMutex > & )
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is too old\n",
|
||||
pHostName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
double tmp = mp->m_dataType - CA_PROTO_PRIORITY_MIN;
|
||||
tmp *= epicsThreadPriorityCAServerHigh - epicsThreadPriorityCAServerLow;
|
||||
tmp /= CA_PROTO_PRIORITY_MAX - CA_PROTO_PRIORITY_MIN;
|
||||
@@ -1243,6 +1253,14 @@ caStatus casStrmClient :: searchResponse (
|
||||
const pvExistReturn & retVal )
|
||||
{
|
||||
if ( retVal.getStatus() != pverExistsHere ) {
|
||||
if (msg.m_dataType == DOREPLY ) {
|
||||
long status = this->out.copyInHeader ( CA_PROTO_NOT_FOUND, 0,
|
||||
msg.m_dataType, msg.m_count, msg.m_cid, msg.m_available, 0 );
|
||||
|
||||
if ( status == S_cas_success ) {
|
||||
this->out.commitMsg ();
|
||||
}
|
||||
}
|
||||
return S_cas_success;
|
||||
}
|
||||
|
||||
@@ -1338,6 +1356,16 @@ caStatus casStrmClient :: searchAction ( epicsGuard < casClientMutex > & guard )
|
||||
const char *pChanName = static_cast <char * > ( this->ctx.getData() );
|
||||
caStatus status;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
if ( this->getCAS().getDebugLevel() > 3u ) {
|
||||
char pHostName[64u];
|
||||
this->hostName ( pHostName, sizeof ( pHostName ) );
|
||||
printf ( "\"%s\" is searching for \"%s\" but is too old\n",
|
||||
pHostName, pChanName );
|
||||
}
|
||||
return S_cas_badProtocol;
|
||||
}
|
||||
|
||||
//
|
||||
// check the sanity of the message
|
||||
//
|
||||
@@ -1407,11 +1435,8 @@ caStatus casStrmClient :: searchAction ( epicsGuard < casClientMutex > & guard )
|
||||
//
|
||||
switch ( pver.getStatus() ) {
|
||||
case pverExistsHere:
|
||||
status = this->searchResponse ( guard, *mp, pver );
|
||||
break;
|
||||
|
||||
case pverDoesNotExistHere:
|
||||
status = S_cas_success;
|
||||
status = this->searchResponse ( guard, *mp, pver );
|
||||
break;
|
||||
|
||||
case pverAsyncCompletion:
|
||||
|
||||
@@ -325,31 +325,12 @@ unsigned lineno
|
||||
static int bad_udp_cmd_action ( caHdrLargeArray *mp,
|
||||
void *pPayload, struct client *pClient )
|
||||
{
|
||||
log_header ("invalid (damaged?) request code from UDP",
|
||||
pClient, mp, pPayload, 0);
|
||||
if (CASDEBUG > 0)
|
||||
log_header ("invalid (damaged?) request code from UDP",
|
||||
pClient, mp, pPayload, 0);
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* udp_echo_action()
|
||||
*/
|
||||
static int udp_echo_action ( caHdrLargeArray *mp,
|
||||
void *pPayload, struct client *pClient )
|
||||
{
|
||||
char *pPayloadOut;
|
||||
int status;
|
||||
SEND_LOCK ( pClient );
|
||||
status = cas_copy_in_header ( pClient, mp->m_cmmd, mp->m_postsize,
|
||||
mp->m_dataType, mp->m_count, mp->m_cid, mp->m_available,
|
||||
( void * ) &pPayloadOut );
|
||||
if ( status == ECA_NORMAL ) {
|
||||
memcpy ( pPayloadOut, pPayload, mp->m_postsize );
|
||||
cas_commit_msg ( pClient, mp->m_postsize );
|
||||
}
|
||||
SEND_UNLOCK ( pClient );
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* bad_tcp_cmd_action()
|
||||
*/
|
||||
@@ -380,6 +361,13 @@ static int tcp_version_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
unsigned epicsPriorityNew;
|
||||
unsigned epicsPrioritySelf;
|
||||
|
||||
client->minor_version_number = mp->m_count;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
DLOG ( 2, ( "CAS: Ignore version from unsupported client %u\n", mp->m_count ) );
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
if ( mp->m_dataType > CA_PROTO_PRIORITY_MAX ) {
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
@@ -465,16 +453,6 @@ static void no_read_access_event ( struct client *pClient,
|
||||
char *pPayloadOut;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* continue to return an exception
|
||||
* on failure to pre v41 clients
|
||||
*/
|
||||
if ( ! CA_V41 ( pClient->minor_version_number ) ) {
|
||||
send_err ( &pevext->msg, ECA_GETFAIL, pClient,
|
||||
RECORD_NAME ( pevext->pciu->dbch ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* New clients recv the status of the
|
||||
* operation directly to the
|
||||
@@ -514,7 +492,6 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
|
||||
struct channel_in_use *pciu = pevext->pciu;
|
||||
const int readAccess = asCheckGet ( pciu->asClientPVT );
|
||||
int status;
|
||||
int v41;
|
||||
int autosize;
|
||||
int local_fl = 0;
|
||||
long item_count;
|
||||
@@ -523,23 +500,7 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
|
||||
|
||||
SEND_LOCK ( pClient );
|
||||
|
||||
/*
|
||||
* New clients recv the status of the
|
||||
* operation directly to the
|
||||
* event/put/get callback.
|
||||
*
|
||||
* The m_cid field in the protocol
|
||||
* header is abused to carry the status,
|
||||
* but get calls still use the
|
||||
* m_cid field to identify the channel
|
||||
*/
|
||||
v41 = CA_V41 ( pClient->minor_version_number );
|
||||
if ( v41 ) {
|
||||
cid = ECA_NORMAL;
|
||||
}
|
||||
else {
|
||||
cid = pciu->cid;
|
||||
}
|
||||
cid = ECA_NORMAL;
|
||||
|
||||
/* If the client has requested a zero element count we interpret this as a
|
||||
* request for all avaiable elements. In this case we initialise the
|
||||
@@ -590,35 +551,22 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
|
||||
if (local_fl) db_delete_field_log(pfl);
|
||||
|
||||
if ( status < 0 ) {
|
||||
/*
|
||||
* I cant wait to redesign this protocol from scratch!
|
||||
*/
|
||||
if ( ! v41 ) {
|
||||
/*
|
||||
* old client & plain get
|
||||
* continue to return an exception
|
||||
* on failure
|
||||
*/
|
||||
send_err ( &pevext->msg, ECA_GETFAIL, pClient, RECORD_NAME ( dbch ) );
|
||||
}
|
||||
else {
|
||||
/* New clients recv the status of the operation directly to the
|
||||
* event/put/get callback.
|
||||
*
|
||||
* Fetched value is set to zero in case they use it even when the
|
||||
* status indicates failure -- unless the client selected autosizing
|
||||
* data, in which case they'd better know what they're doing!
|
||||
*
|
||||
* The m_cid field in the protocol header is abused to carry the
|
||||
* status */
|
||||
if (autosize) {
|
||||
payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
|
||||
cas_set_header_count(pClient, 0);
|
||||
}
|
||||
memset ( pPayload, 0, payload_size );
|
||||
cas_set_header_cid ( pClient, ECA_GETFAIL );
|
||||
cas_commit_msg ( pClient, payload_size );
|
||||
/* Clients recv the status of the operation directly to the
|
||||
* event/put/get callback. (from CA_V41())
|
||||
*
|
||||
* Fetched value is set to zero in case they use it even when the
|
||||
* status indicates failure -- unless the client selected autosizing
|
||||
* data, in which case they'd better know what they're doing!
|
||||
*
|
||||
* The m_cid field in the protocol header is abused to carry the
|
||||
* status */
|
||||
if (autosize) {
|
||||
payload_size = dbr_size_n(pevext->msg.m_dataType, 0);
|
||||
cas_set_header_count(pClient, 0);
|
||||
}
|
||||
memset ( pPayload, 0, payload_size );
|
||||
cas_set_header_cid ( pClient, ECA_GETFAIL );
|
||||
cas_commit_msg ( pClient, payload_size );
|
||||
}
|
||||
else {
|
||||
int cacStatus = caNetConvert (
|
||||
@@ -668,7 +616,6 @@ static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *p
|
||||
ca_uint32_t payloadSize;
|
||||
void *pPayload;
|
||||
int status;
|
||||
int v41;
|
||||
int local_fl = 0;
|
||||
db_field_log *pfl = NULL;
|
||||
|
||||
@@ -700,14 +647,8 @@ static int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *p
|
||||
/*
|
||||
* verify read access
|
||||
*/
|
||||
v41 = CA_V41 ( pClient->minor_version_number );
|
||||
if ( ! readAccess ) {
|
||||
if ( v41 ) {
|
||||
status = ECA_NORDACCESS;
|
||||
}
|
||||
else{
|
||||
status = ECA_GETFAIL;
|
||||
}
|
||||
status = ECA_NORDACCESS;
|
||||
send_err ( mp, status,
|
||||
pClient, RECORD_NAME ( pciu->dbch ) );
|
||||
SEND_UNLOCK ( pClient );
|
||||
@@ -809,7 +750,6 @@ static int write_action ( caHdrLargeArray *mp,
|
||||
void *pPayload, struct client *client )
|
||||
{
|
||||
struct channel_in_use *pciu;
|
||||
int v41;
|
||||
int status;
|
||||
long dbStatus;
|
||||
void *asWritePvt;
|
||||
@@ -821,13 +761,7 @@ static int write_action ( caHdrLargeArray *mp,
|
||||
}
|
||||
|
||||
if(!rsrvCheckPut(pciu)){
|
||||
v41 = CA_V41(client->minor_version_number);
|
||||
if(v41){
|
||||
status = ECA_NOWTACCESS;
|
||||
}
|
||||
else{
|
||||
status = ECA_PUTFAIL;
|
||||
}
|
||||
status = ECA_NOWTACCESS;
|
||||
SEND_LOCK(client);
|
||||
send_err(
|
||||
mp,
|
||||
@@ -1192,19 +1126,10 @@ static void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type)
|
||||
static void access_rights_reply ( struct channel_in_use * pciu )
|
||||
{
|
||||
unsigned ar;
|
||||
int v41;
|
||||
int status;
|
||||
|
||||
assert ( pciu->client->proto!=IPPROTO_UDP );
|
||||
|
||||
/*
|
||||
* noop if this is an old client
|
||||
*/
|
||||
v41 = CA_V41 ( pciu->client->minor_version_number );
|
||||
if ( ! v41 ){
|
||||
return;
|
||||
}
|
||||
|
||||
ar = 0; /* none */
|
||||
if ( asCheckGet ( pciu->asClientPVT ) ) {
|
||||
ar |= CA_PROTO_ACCESS_RIGHT_READ;
|
||||
@@ -1231,39 +1156,38 @@ static void access_rights_reply ( struct channel_in_use * pciu )
|
||||
*/
|
||||
static void claim_ciu_reply ( struct channel_in_use * pciu )
|
||||
{
|
||||
int v42 = CA_V42 ( pciu->client->minor_version_number );
|
||||
int status;
|
||||
ca_uint32_t nElem;
|
||||
long dbElem;
|
||||
|
||||
access_rights_reply ( pciu );
|
||||
if ( v42 ) {
|
||||
int status;
|
||||
ca_uint32_t nElem;
|
||||
long dbElem;
|
||||
SEND_LOCK ( pciu->client );
|
||||
dbElem = dbChannelFinalElements(pciu->dbch);
|
||||
if ( dbElem < 0 ) {
|
||||
nElem = 0;
|
||||
}
|
||||
else {
|
||||
if ( ! CA_V49 ( pciu->client->minor_version_number ) ) {
|
||||
if ( dbElem >= 0xffff ) {
|
||||
nElem = 0xfffe;
|
||||
}
|
||||
else {
|
||||
nElem = (ca_uint32_t) dbElem;
|
||||
}
|
||||
|
||||
SEND_LOCK ( pciu->client );
|
||||
dbElem = dbChannelFinalElements(pciu->dbch);
|
||||
if ( dbElem < 0 ) {
|
||||
nElem = 0;
|
||||
}
|
||||
else {
|
||||
if ( ! CA_V49 ( pciu->client->minor_version_number ) ) {
|
||||
if ( dbElem >= 0xffff ) {
|
||||
nElem = 0xfffe;
|
||||
}
|
||||
else {
|
||||
nElem = (ca_uint32_t) dbElem;
|
||||
}
|
||||
}
|
||||
status = cas_copy_in_header (
|
||||
pciu->client, CA_PROTO_CREATE_CHAN, 0u,
|
||||
dbChannelFinalCAType(pciu->dbch), nElem, pciu->cid,
|
||||
pciu->sid, NULL );
|
||||
if ( status == ECA_NORMAL ) {
|
||||
cas_commit_msg ( pciu->client, 0u );
|
||||
else {
|
||||
nElem = (ca_uint32_t) dbElem;
|
||||
}
|
||||
SEND_UNLOCK(pciu->client);
|
||||
}
|
||||
status = cas_copy_in_header (
|
||||
pciu->client, CA_PROTO_CREATE_CHAN, 0u,
|
||||
dbChannelFinalCAType(pciu->dbch), nElem, pciu->cid,
|
||||
pciu->sid, NULL );
|
||||
if ( status == ECA_NORMAL ) {
|
||||
cas_commit_msg ( pciu->client, 0u );
|
||||
}
|
||||
SEND_UNLOCK(pciu->client);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1283,83 +1207,51 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
*/
|
||||
client->minor_version_number = mp->m_available;
|
||||
|
||||
if (CA_V44(client->minor_version_number)) {
|
||||
struct dbChannel *dbch;
|
||||
char *pName = (char *) pPayload;
|
||||
if (!CA_V44(client->minor_version_number))
|
||||
return RSRV_ERROR; /* shouldn't actually get here due to VSUPPORTED test in camessage() */
|
||||
|
||||
/*
|
||||
* check the sanity of the message
|
||||
*/
|
||||
if (mp->m_postsize<=1) {
|
||||
log_header ( "empty PV name in UDP search request?",
|
||||
client, mp, pPayload, 0 );
|
||||
return RSRV_OK;
|
||||
}
|
||||
pName[mp->m_postsize-1] = '\0';
|
||||
struct dbChannel *dbch;
|
||||
char *pName = (char *) pPayload;
|
||||
|
||||
dbch = dbChannel_create (pName);
|
||||
if (!dbch) {
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
|
||||
pName, dbChannelCAType(dbch), dbChannelElements(dbch)) );
|
||||
|
||||
pciu = casCreateChannel (
|
||||
client,
|
||||
dbch,
|
||||
mp->m_cid);
|
||||
if (!pciu) {
|
||||
log_header ("no memory to create new channel",
|
||||
client, mp, pPayload, 0);
|
||||
SEND_LOCK(client);
|
||||
send_err(mp,
|
||||
ECA_ALLOCMEM,
|
||||
client,
|
||||
RECORD_NAME(dbch));
|
||||
SEND_UNLOCK(client);
|
||||
dbChannelDelete(dbch);
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
/*
|
||||
* check the sanity of the message
|
||||
*/
|
||||
if (mp->m_postsize<=1) {
|
||||
log_header ( "empty PV name in UDP search request?",
|
||||
client, mp, pPayload, 0 );
|
||||
return RSRV_OK;
|
||||
}
|
||||
else {
|
||||
epicsMutexMustLock(client->chanListLock);
|
||||
/*
|
||||
* clients which dont claim their
|
||||
* channel in use block prior to
|
||||
* timeout must reconnect
|
||||
*/
|
||||
pciu = MPTOPCIU(mp);
|
||||
if(!pciu){
|
||||
errlogPrintf("CAS: client timeout disconnect id=%d\n",
|
||||
mp->m_cid);
|
||||
epicsMutexUnlock(client->chanListLock);
|
||||
SEND_LOCK(client);
|
||||
send_err(
|
||||
mp,
|
||||
ECA_INTERNAL,
|
||||
client,
|
||||
"old connect protocol timed out");
|
||||
SEND_UNLOCK(client);
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
pName[mp->m_postsize-1] = '\0';
|
||||
|
||||
/*
|
||||
* remove channel in use block from
|
||||
* the UDP client where it could time
|
||||
* out and place it on the client
|
||||
* who is claiming it
|
||||
*/
|
||||
ellDelete(
|
||||
&client->chanList,
|
||||
&pciu->node);
|
||||
epicsMutexUnlock(client->chanListLock);
|
||||
dbch = dbChannel_create (pName);
|
||||
if (!dbch) {
|
||||
SEND_LOCK(client);
|
||||
status = cas_copy_in_header ( client,
|
||||
CA_PROTO_CREATE_CH_FAIL, 0, 0, 0, mp->m_cid, 0, NULL );
|
||||
if (status == ECA_NORMAL)
|
||||
cas_commit_msg ( client, 0u );
|
||||
SEND_UNLOCK(client);
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
epicsMutexMustLock(client->chanListLock);
|
||||
pciu->state = rsrvCS_pendConnectResp;
|
||||
pciu->client = client;
|
||||
ellAdd(&client->chanList, &pciu->node);
|
||||
epicsMutexUnlock(client->chanListLock);
|
||||
DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
|
||||
pName, dbChannelCAType(dbch), dbChannelElements(dbch)) );
|
||||
|
||||
pciu = casCreateChannel (
|
||||
client,
|
||||
dbch,
|
||||
mp->m_cid);
|
||||
if (!pciu) {
|
||||
log_header ("no memory to create new channel",
|
||||
client, mp, pPayload, 0);
|
||||
SEND_LOCK(client);
|
||||
send_err(mp,
|
||||
ECA_ALLOCMEM,
|
||||
client,
|
||||
RECORD_NAME(dbch));
|
||||
SEND_UNLOCK(client);
|
||||
dbChannelDelete(dbch);
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2212,14 +2104,18 @@ static void search_fail_reply ( caHdrLargeArray *mp, void *pPayload, struct clie
|
||||
*/
|
||||
static int udp_version_action ( caHdrLargeArray *mp, void *pPayload, struct client *client )
|
||||
{
|
||||
if ( mp->m_count != 0 ) {
|
||||
client->minor_version_number = mp->m_count;
|
||||
if ( CA_V411 ( mp->m_count ) ) {
|
||||
client->seqNoOfReq = mp->m_cid;
|
||||
}
|
||||
else {
|
||||
client->seqNoOfReq = 0;
|
||||
}
|
||||
client->minor_version_number = mp->m_count;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
DLOG ( 2, ( "CAS: Ignore version from unsupported client %u\n", mp->m_count ) );
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
if ( CA_V411 ( mp->m_count ) ) {
|
||||
client->seqNoOfReq = mp->m_cid;
|
||||
}
|
||||
else {
|
||||
client->seqNoOfReq = 0;
|
||||
}
|
||||
return RSRV_OK;
|
||||
}
|
||||
@@ -2263,6 +2159,11 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
|
||||
size_t spaceNeeded;
|
||||
size_t reasonableMonitorSpace = 10;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
DLOG ( 2, ( "CAS: Ignore search from unsupported client %u\n", mp->m_count ) );
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the sanity of the message
|
||||
*/
|
||||
@@ -2276,8 +2177,6 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
|
||||
/* Exit quickly if channel not on this node */
|
||||
if (dbChannelTest(pName)) {
|
||||
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
|
||||
if (mp->m_dataType == DOREPLY)
|
||||
search_fail_reply ( mp, pPayload, client );
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
@@ -2289,10 +2188,7 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
|
||||
spaceNeeded = sizeof (struct channel_in_use) +
|
||||
reasonableMonitorSpace * sizeof (struct event_ext);
|
||||
if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
|
||||
SEND_LOCK(client);
|
||||
send_err ( mp, ECA_ALLOCMEM, client, "Server memory exhausted" );
|
||||
SEND_UNLOCK(client);
|
||||
return RSRV_OK;
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2311,36 +2207,8 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
|
||||
type = ca_server_port;
|
||||
}
|
||||
else {
|
||||
struct dbChannel *dbch;
|
||||
struct channel_in_use *pchannel;
|
||||
|
||||
dbch = dbChannel_create(pName);
|
||||
if (!dbch) {
|
||||
DLOG ( 2, ( "CAS: dbChannel Test of \"%s\" OK but Create failed\n", pName ) );
|
||||
if (mp->m_dataType == DOREPLY)
|
||||
search_fail_reply ( mp, pPayload, client );
|
||||
return RSRV_OK;
|
||||
}
|
||||
pchannel = casCreateChannel ( client, dbch, mp->m_cid );
|
||||
if (!pchannel) {
|
||||
SEND_LOCK(client);
|
||||
send_err ( mp, ECA_ALLOCMEM, client,
|
||||
RECORD_NAME ( dbch ) );
|
||||
SEND_UNLOCK ( client );
|
||||
dbChannelDelete(dbch);
|
||||
return RSRV_OK;
|
||||
}
|
||||
sid = pchannel->sid;
|
||||
if ( dbChannelFinalElements(dbch) < 0 ) {
|
||||
count = 0;
|
||||
}
|
||||
else if ( dbChannelFinalElements(dbch) > 0xffff ) {
|
||||
count = 0xfffe;
|
||||
}
|
||||
else {
|
||||
count = (ca_uint16_t) dbChannelFinalElements(dbch);
|
||||
}
|
||||
type = (ca_uint16_t) dbChannelFinalCAType(dbch);
|
||||
/* shouldn't actually get here due to VSUPPORTED test */
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
SEND_LOCK ( client );
|
||||
@@ -2378,6 +2246,11 @@ static int search_reply_tcp (
|
||||
size_t spaceNeeded;
|
||||
size_t reasonableMonitorSpace = 10;
|
||||
|
||||
if (!CA_VSUPPORTED(mp->m_count)) {
|
||||
DLOG ( 2, ( "CAS: Ignore search from unsupported client %u\n", mp->m_count ) );
|
||||
return RSRV_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the sanity of the message
|
||||
*/
|
||||
@@ -2490,7 +2363,7 @@ static const pProtoStubUDP udpJumpTable[] =
|
||||
bad_udp_cmd_action,
|
||||
bad_udp_cmd_action,
|
||||
bad_udp_cmd_action,
|
||||
udp_echo_action,
|
||||
bad_udp_cmd_action,
|
||||
bad_udp_cmd_action,
|
||||
bad_udp_cmd_action,
|
||||
bad_udp_cmd_action,
|
||||
@@ -2561,15 +2434,37 @@ int camessage ( struct client *client )
|
||||
pBody = ( void * ) ( mp + 1 );
|
||||
}
|
||||
|
||||
/* ignore deprecated clients, but let newer clients identify themselves. */
|
||||
if (msg.m_cmmd!=CA_PROTO_VERSION && !CA_VSUPPORTED(client->minor_version_number)) {
|
||||
if (client->proto==IPPROTO_TCP) {
|
||||
/* log and error for too old clients, but keep the connection open to avoid a
|
||||
* re-connect loop.
|
||||
*/
|
||||
send_err ( &msg, ECA_DEFUNCT, client,
|
||||
"CAS: Client version %u too old", client->minor_version_number );
|
||||
log_header ( "CAS: Client version too old",
|
||||
client, &msg, 0, nmsg );
|
||||
client->recvBytesToDrain = msgsize - bytes_left;
|
||||
client->recv.stk = client->recv.cnt;
|
||||
status = RSRV_OK;
|
||||
} else {
|
||||
/* silently ignore UDP from old clients */
|
||||
status = RSRV_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* disconnect clients that dont send 8 byte
|
||||
* aligned payloads
|
||||
*/
|
||||
if ( msgsize & 0x7 ) {
|
||||
send_err ( &msg, ECA_INTERNAL, client,
|
||||
"CAS: Missaligned protocol rejected" );
|
||||
log_header ( "CAS: Missaligned protocol rejected",
|
||||
client, &msg, 0, nmsg );
|
||||
if (client->proto==IPPROTO_TCP) {
|
||||
send_err ( &msg, ECA_INTERNAL, client,
|
||||
"CAS: Missaligned protocol rejected" );
|
||||
log_header ( "CAS: Missaligned protocol rejected",
|
||||
client, &msg, 0, nmsg );
|
||||
}
|
||||
status = RSRV_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -2583,11 +2478,13 @@ int camessage ( struct client *client )
|
||||
if ( msgsize > client->recv.maxstk ) {
|
||||
casExpandRecvBuffer ( client, msgsize );
|
||||
if ( msgsize > client->recv.maxstk ) {
|
||||
send_err ( &msg, ECA_TOLARGE, client,
|
||||
"CAS: Server unable to load large request message. Max bytes=%lu",
|
||||
rsrvSizeofLargeBufTCP );
|
||||
log_header ( "CAS: server unable to load large request message",
|
||||
client, &msg, 0, nmsg );
|
||||
if (client->proto==IPPROTO_TCP) {
|
||||
send_err ( &msg, ECA_TOLARGE, client,
|
||||
"CAS: Server unable to load large request message. Max bytes=%lu",
|
||||
rsrvSizeofLargeBufTCP );
|
||||
log_header ( "CAS: server unable to load large request message",
|
||||
client, &msg, 0, nmsg );
|
||||
}
|
||||
assert ( client->recv.cnt <= client->recv.maxstk );
|
||||
assert ( msgsize >= bytes_left );
|
||||
client->recvBytesToDrain = msgsize - bytes_left;
|
||||
|
||||
@@ -197,7 +197,7 @@ void cast_server(void *pParm)
|
||||
client->recv.stk = 0ul;
|
||||
epicsTimeGetCurrent(&client->time_at_last_recv);
|
||||
|
||||
client->minor_version_number = 0;
|
||||
client->minor_version_number = CA_UKN_MINOR_VERSION;
|
||||
client->seqNoOfReq = 0;
|
||||
|
||||
/*
|
||||
@@ -247,7 +247,7 @@ void cast_server(void *pParm)
|
||||
epicsPrintf ("CAS: message received at %s\n", buf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (CASDEBUG>0){
|
||||
char buf[40];
|
||||
|
||||
ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
|
||||
|
||||
Reference in New Issue
Block a user