diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index 75cc32136..54f91eba2 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -493,12 +493,12 @@ LOCAL void read_reply ( void *pArg, struct dbAddr *paddr, struct event_ext *pevext = pArg; struct client *pClient = pevext->pciu->client; struct channel_in_use *pciu = pevext->pciu; + const int readAccess = asCheckGet ( pciu->asClientPVT ); int status; int strcnt; int v41; - if ( pevext->send_lock ) - SEND_LOCK ( pClient ); + SEND_LOCK ( pClient ); /* * New clients recv the status of the @@ -526,22 +526,19 @@ LOCAL void read_reply ( void *pArg, struct dbAddr *paddr, "server unable to load read (or subscription update) response into protocol buffer PV=\"%s\" max bytes=%u", RECORD_NAME ( paddr ), rsrvSizeofLargeBufTCP ); if ( ! eventsRemaining ) - cas_send_bs_msg ( pClient, ! pevext->send_lock ); - if ( pevext->send_lock ) - SEND_UNLOCK ( pClient ); + cas_send_bs_msg ( pClient, FALSE ); + SEND_UNLOCK ( pClient ); return; } /* * verify read access */ - if ( ! asCheckGet ( pciu->asClientPVT ) ) { + if ( ! readAccess ) { no_read_access_event ( pClient, pevext ); if ( ! eventsRemaining ) - cas_send_bs_msg ( pClient, !pevext->send_lock ); - if ( pevext->send_lock ) { - SEND_UNLOCK ( pClient ); - } + cas_send_bs_msg ( pClient, FALSE ); + SEND_UNLOCK ( pClient ); return; } @@ -606,10 +603,9 @@ LOCAL void read_reply ( void *pArg, struct dbAddr *paddr, * them up like db requests when the OPI does not keep up. */ if ( ! eventsRemaining ) - cas_send_bs_msg ( pClient, ! pevext->send_lock ); + cas_send_bs_msg ( pClient, FALSE ); - if ( pevext->send_lock ) - SEND_UNLOCK ( pClient ); + SEND_UNLOCK ( pClient ); return; } @@ -619,14 +615,14 @@ LOCAL void read_reply ( void *pArg, struct dbAddr *paddr, */ LOCAL int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *pClient ) { - struct channel_in_use *pciu; + struct channel_in_use *pciu = MPTOPCIU ( mp ); + const int readAccess = asCheckGet ( pciu->asClientPVT ); ca_uint32_t payloadSize; void *pPayload; int status; int strcnt; int v41; - pciu = MPTOPCIU ( mp ); if ( ! pciu ) { logBadId ( pClient, mp, 0 ); return RSRV_ERROR; @@ -655,7 +651,7 @@ LOCAL int read_action ( caHdrLargeArray *mp, void *pPayloadIn, struct client *pC * verify read access */ v41 = CA_V41 ( pClient->minor_version_number ); - if ( ! asCheckGet ( pciu->asClientPVT ) ) { + if ( ! readAccess ) { if ( v41 ) { status = ECA_NORDACCESS; } @@ -719,7 +715,6 @@ LOCAL int read_notify_action ( caHdrLargeArray *mp, void *pPayload, struct clien evext.msg = *mp; evext.pciu = pciu; - evext.send_lock = TRUE; evext.pdbev = NULL; evext.size = dbr_size_n ( mp->m_dataType, mp->m_count ); @@ -1038,7 +1033,7 @@ unsigned cid } epicsMutexMustLock( client->chanListLock ); - pchannel->state = rsrvCS_inService; + pchannel->state = rsrvCS_pendConnectResp; ellAdd ( &client->chanList, &pchannel->node ); epicsMutexUnlock ( client->chanListLock ); @@ -1071,9 +1066,16 @@ LOCAL void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type) { case asClientCOAR: { + const int readAccess = asCheckGet ( pciu->asClientPVT ); unsigned sigReq = 0; epicsMutexMustLock ( pclient->chanListLock ); + if ( pciu->state == rsrvCS_pendConnectResp ) { + ellDelete ( &pclient->chanList, &pciu->node ); + pciu->state = rsrvCS_pendConnectRespUpdatePendAR; + ellAdd ( &pclient->chanPendingUpdateARList, &pciu->node ); + sigReq = 1; + } if ( pciu->state == rsrvCS_inService ) { ellDelete ( &pclient->chanList, &pciu->node ); pciu->state = rsrvCS_inServiceUpdatePendAR; @@ -1083,23 +1085,22 @@ LOCAL void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type) epicsMutexUnlock ( pclient->chanListLock ); /* - * Update all event call backs - */ + * Update all event call backs + */ epicsMutexMustLock(pclient->eventqLock); - for (pevext = (struct event_ext *) ellFirst(&pciu->eventq); pevext; pevext = (struct event_ext *) ellNext(&pevext->node)){ - int readAccess = asCheckGet(pciu->asClientPVT); - - if(pevext->pdbev && !readAccess){ - db_post_single_event(pevext->pdbev); - db_event_disable(pevext->pdbev); - } - else if(pevext->pdbev && readAccess){ - db_event_enable(pevext->pdbev); - db_post_single_event(pevext->pdbev); + if ( pevext->pdbev ) { + if ( readAccess ){ + db_event_enable ( pevext->pdbev ); + db_post_single_event ( pevext->pdbev ); + } + else { + db_post_single_event ( pevext->pdbev ); + db_event_disable ( pevext->pdbev ); + } } } epicsMutexUnlock(pclient->eventqLock); @@ -1155,13 +1156,50 @@ LOCAL void access_rights_reply ( struct channel_in_use * pciu ) SEND_UNLOCK ( pciu->client ); } +/* + * claim_ciu_reply() + */ +LOCAL void claim_ciu_reply ( struct channel_in_use * pciu ) +{ + int v42 = CA_V42 ( pciu->client->minor_version_number ); + access_rights_reply ( pciu ); + if ( v42 ) { + int status; + ca_uint32_t nElem; + SEND_LOCK ( pciu->client ); + if ( pciu->addr.no_elements < 0 ) { + nElem = 0; + } + else { + if ( ! CA_V49 ( pciu->client->minor_version_number ) ) { + if ( pciu->addr.no_elements >= 0xffff ) { + nElem = 0xfffe; + } + else { + nElem = (ca_uint32_t) pciu->addr.no_elements; + } + } + else { + nElem = (ca_uint32_t) pciu->addr.no_elements; + } + } + status = cas_copy_in_header ( + pciu->client, CA_PROTO_CREATE_CHAN, 0u, + pciu->addr.dbr_field_type, nElem, pciu->cid, + pciu->sid, NULL ); + if ( status == ECA_NORMAL ) { + cas_commit_msg ( pciu->client, 0u ); + } + SEND_UNLOCK(pciu->client); + } +} + /* * claim_ciu_action() */ LOCAL int claim_ciu_action ( caHdrLargeArray *mp, void *pPayload, client *client ) { - int v42; int status; struct channel_in_use *pciu; @@ -1263,7 +1301,7 @@ LOCAL int claim_ciu_action ( caHdrLargeArray *mp, epicsMutexUnlock(prsrv_cast_client->chanListLock); epicsMutexMustLock(client->chanListLock); - pciu->state = rsrvCS_inService; + pciu->state = rsrvCS_pendConnectResp; pciu->client = client; ellAdd(&client->chanList, &pciu->node); epicsMutexUnlock(client->chanListLock); @@ -1293,19 +1331,17 @@ LOCAL int claim_ciu_action ( caHdrLargeArray *mp, */ asPutClientPvt(pciu->asClientPVT, pciu); - v42 = CA_V42(client->minor_version_number); - /* * register for asynch updates of access rights changes */ status = asRegisterClientCallback( pciu->asClientPVT, casAccessRightsCB); - if(status == S_asLib_asNotActive){ + if ( status == S_asLib_asNotActive ) { /* - * force the initial update + * force the initial AR update followed by claim response */ - access_rights_reply(pciu); + claim_ciu_reply ( pciu ); } else if (status!=0) { log_header ("No room for access security state change subscription", @@ -1316,37 +1352,6 @@ LOCAL int claim_ciu_action ( caHdrLargeArray *mp, SEND_UNLOCK(client); return RSRV_ERROR; } - - if(v42){ - ca_uint32_t nElem; - - SEND_LOCK ( client ); - - if ( pciu->addr.no_elements < 0 ) { - nElem = 0; - } - else { - if ( ! CA_V49 ( client->minor_version_number ) ) { - if ( pciu->addr.no_elements >= 0xffff ) { - nElem = 0xfffe; - } - else { - nElem = (ca_uint32_t) pciu->addr.no_elements; - } - } - else { - nElem = (ca_uint32_t) pciu->addr.no_elements; - } - } - status = cas_copy_in_header ( - client, CA_PROTO_CREATE_CHAN, 0u, - pciu->addr.dbr_field_type, nElem, pciu->cid, - pciu->sid, NULL ); - if ( status == ECA_NORMAL ) { - cas_commit_msg ( client, 0u ); - } - SEND_UNLOCK(client); - } return RSRV_OK; } @@ -1479,9 +1484,19 @@ LOCAL void sendAllUpdateAS ( struct client *client ) pciu = ( struct channel_in_use * ) ellGet ( & client->chanPendingUpdateARList ); while ( pciu ) { - access_rights_reply ( pciu ); + if ( pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) { + claim_ciu_reply ( pciu ); + } + else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ) { + access_rights_reply ( pciu ); + } + else { + errlogPrintf ( + "%s at %d: corrupt channel state detected durring AR update\n", + __FILE__, __LINE__); + } pciu->state = rsrvCS_inService; - ellAdd ( & client->chanList, &pciu->node ); + ellAdd ( & client->chanList, & pciu->node ); pciu = ( struct channel_in_use * ) ellGet ( & client->chanPendingUpdateARList ); } @@ -1501,7 +1516,6 @@ void rsrv_extra_labor ( void * pArg ) cas_send_bs_msg ( pClient, TRUE ); } - /* * putNotifyErrorReply */ @@ -1825,7 +1839,6 @@ LOCAL int event_add_action (caHdrLargeArray *mp, void *pPayload, struct client * pevext->msg = *mp; pevext->pciu = pciu; - pevext->send_lock = TRUE; pevext->size = dbr_size_n(mp->m_dataType, mp->m_count); pevext->mask = ntohs ( pmi->m_mask ); @@ -1945,10 +1958,12 @@ LOCAL int clear_channel_reply ( caHdrLargeArray *mp, SEND_UNLOCK(client); epicsMutexMustLock ( client->chanListLock ); - if ( pciu->state == rsrvCS_inService ) { + if ( pciu->state == rsrvCS_inService || +! pciu->state == rsrvCS_pendConnectResp ) { ellDelete ( &client->chanList, &pciu->node ); } - else if ( pciu->state == rsrvCS_inServiceUpdatePendAR ) { + else if ( pciu->state == rsrvCS_inServiceUpdatePendAR || +! pciu->state == rsrvCS_pendConnectRespUpdatePendAR ) { ellDelete ( &client->chanPendingUpdateARList, &pciu->node ); } else { diff --git a/src/rsrv/server.h b/src/rsrv/server.h index 5c99a3793..876f075f9 100644 --- a/src/rsrv/server.h +++ b/src/rsrv/server.h @@ -104,8 +104,11 @@ typedef struct client { enum rsrvChanState { rsrvCS_invalid, - rsrvCS_inService, - rsrvCS_inServiceUpdatePendAR }; + rsrvCS_pendConnectResp, + rsrvCS_inService, + rsrvCS_pendConnectRespUpdatePendAR, + rsrvCS_inServiceUpdatePendAR +}; /* * per channel structure @@ -136,7 +139,6 @@ struct event_ext { unsigned size; /* for speed */ unsigned mask; char modified; /* mod & ev flw ctrl enbl */ - char send_lock; /* lock send buffer */ }; /* NOTE: external used so they remember the state across loads */