diff --git a/src/ca/client/caProto.h b/src/ca/client/caProto.h index f61f52e08..781c89b34 100644 --- a/src/ca/client/caProto.h +++ b/src/ca/client/caProto.h @@ -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 diff --git a/src/ca/legacy/pcas/generic/casDGClient.cc b/src/ca/legacy/pcas/generic/casDGClient.cc index 4fca74dbd..4cc05be32 100644 --- a/src/ca/legacy/pcas/generic/casDGClient.cc +++ b/src/ca/legacy/pcas/generic/casDGClient.cc @@ -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 ( 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 ( mp->m_count ); if ( CA_V411 ( mp->m_count ) ) { diff --git a/src/ca/legacy/pcas/generic/casStrmClient.cc b/src/ca/legacy/pcas/generic/casStrmClient.cc index ff12e889e..b9f886a99 100644 --- a/src/ca/legacy/pcas/generic/casStrmClient.cc +++ b/src/ca/legacy/pcas/generic/casStrmClient.cc @@ -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 ( 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: diff --git a/src/ioc/rsrv/camessage.c b/src/ioc/rsrv/camessage.c index b13883b5a..a174cb23f 100644 --- a/src/ioc/rsrv/camessage.c +++ b/src/ioc/rsrv/camessage.c @@ -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; diff --git a/src/ioc/rsrv/cast_server.c b/src/ioc/rsrv/cast_server.c index b6bed8484..be5ec15c6 100644 --- a/src/ioc/rsrv/cast_server.c +++ b/src/ioc/rsrv/cast_server.c @@ -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));