From 94ab686e4cf3a3d8852ffa8ce27f6bbe73f1a7de Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Sat, 17 Jul 1999 00:40:58 +0000 Subject: [PATCH] merged changes from R3.13.1 patch branch --- src/rsrv/camessage.c | 3474 +++++++++++++++++++------------------- src/rsrv/camsgtask.c | 24 +- src/rsrv/caserverio.c | 2 +- src/rsrv/caservertask.c | 28 +- src/rsrv/cast_server.c | 359 ++-- src/rsrv/online_notify.c | 4 +- 6 files changed, 1923 insertions(+), 1968 deletions(-) diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index 30b301ba9..06b8380a1 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -70,1306 +70,415 @@ static char *sccsId = "%W% %G%"; #include "ellLib.h" #include "freeList.h" #include "caerr.h" +#include "bsdSocketResource.h" #include "server.h" -#define LOCAL - static caHdr nill_msg; #define RECORD_NAME(PADDR) ((PADDR)->precord->name) -LOCAL void clear_channel_reply( -caHdr *mp, -struct client *client -); +LOCAL EVENTFUNC read_reply; -LOCAL void event_cancel_reply( -caHdr *mp, -struct client *client -); +#define logBadId(CLIENT, MP)\ +logBadIdWithFileAndLineno(CLIENT, MP, __FILE__, __LINE__) -LOCAL EVENTFUNC read_reply; +#if 0 +/* + * casMalloc() + * + * (dont drop below some max block threshold) + */ +LOCAL void *casMalloc(size_t size) +{ + if (casBelowMaxBlockThresh) { + return NULL; + } + return malloc(size); +} +#endif -LOCAL void read_sync_reply( -caHdr *mp, -struct client *client -); +/* + * casCalloc() + * + * (dont drop below some max block threshold) + */ +LOCAL void *casCalloc(size_t count, size_t size) +{ + if (casBelowMaxBlockThresh) { + return NULL; + } + return calloc(count, size); +} -LOCAL void search_reply( -caHdr *mp, -struct client *client -); +/* + * MPTOPCIU() + * + * used to be a macro + */ +LOCAL struct channel_in_use *MPTOPCIU (const caHdr *mp) +{ + struct channel_in_use *pciu; + const unsigned id = mp->m_cid; -LOCAL void search_fail_reply( -caHdr *mp, -struct client *client -); + FASTLOCK(&clientQlock); + pciu = bucketLookupItemUnsignedId (pCaBucket, &id); + FASTUNLOCK(&clientQlock); + return pciu; +} + +/* send_err() + * + * reflect error msg back to the client + * + * send buffer lock must be on while in this routine + * + */ LOCAL void send_err( -caHdr *curp, -int status, -struct client *client, -char *footnote, +const caHdr *curp, +int status, +struct client *client, +const char *pformat, ... -); +) +{ + va_list args; + struct channel_in_use *pciu; + int size; + caHdr *reply; + char *pMsgString; -LOCAL void log_header( -caHdr *mp, -int mnum -); + va_start(args, pformat); -LOCAL void event_add_action( -caHdr *mp, -struct client *client -); + /* + * allocate plenty of space for a sprintf() buffer + */ + reply = (caHdr *) ALLOC_MSG(client, 512); + if (!reply){ + int logMsgArgs[6]; + size_t i; + for(i=0; i< NELEMENTS(logMsgArgs); i++){ + logMsgArgs[i] = va_arg(args, int); + } + + logMsg( "caserver: Unable to deliver err msg to client => \"%s\"\n", + (int) ca_message(status), + NULL, + NULL, + NULL, + NULL, + NULL); + logMsg( + (char *) pformat, + logMsgArgs[0], + logMsgArgs[1], + logMsgArgs[2], + logMsgArgs[3], + logMsgArgs[4], + logMsgArgs[5]); + + return; + } + + reply[0] = nill_msg; + reply[0].m_cmmd = CA_PROTO_ERROR; + reply[0].m_available = status; + + switch (curp->m_cmmd) { + case CA_PROTO_EVENT_ADD: + case CA_PROTO_EVENT_CANCEL: + case CA_PROTO_READ: + case CA_PROTO_READ_NOTIFY: + case CA_PROTO_WRITE: + case CA_PROTO_WRITE_NOTIFY: + /* + * + * Verify the channel + * + */ + pciu = MPTOPCIU(curp); + if(pciu){ + reply->m_cid = (unsigned long) pciu->cid; + } + else{ + reply->m_cid = ~0L; + } + break; + + case CA_PROTO_SEARCH: + reply->m_cid = curp->m_cid; + break; + + case CA_PROTO_EVENTS_ON: + case CA_PROTO_EVENTS_OFF: + case CA_PROTO_READ_SYNC: + case CA_PROTO_SNAPSHOT: + default: + reply->m_cid = ~0L; + break; + } + + /* + * copy back the request protocol + * (in network byte order) + */ + reply[1].m_postsize = htons (curp->m_postsize); + reply[1].m_cmmd = htons (curp->m_cmmd); + reply[1].m_type = htons (curp->m_type); + reply[1].m_count = htons (curp->m_count); + reply[1].m_cid = curp->m_cid; + reply[1].m_available = curp->m_available; + + /* + * add their context string into the protocol + */ + pMsgString = (char *) (reply+2); + status = vsprintf(pMsgString, pformat, args); + + /* + * force string post size to be the true size rounded to even + * boundary + */ + size = strlen(pMsgString)+1; + size += sizeof(*curp); + reply->m_postsize = size; + END_MSG(client); +} + +/* log_header() + * + * Debug aid - print the header part of a message. + * + */ +LOCAL void log_header ( + const char *pContext, + struct client *client, + const caHdr *mp, + int mnum +) +{ + struct channel_in_use *pciu; + char hostName[256]; + + ipAddrToA (&client->addr, hostName, sizeof(hostName)); + + pciu = MPTOPCIU(mp); + + if (pContext) { + epicsPrintf ( +"CAS: request from %s => \"%s\"\n", + hostName, pContext); + } + + epicsPrintf ( +"CAS: Request from %s => cmmd=%d cid=0x%x type=%d count=%d postsize=%u\n", + hostName, mp->m_cmmd, mp->m_cid, mp->m_type, mp->m_count, mp->m_postsize); + + + epicsPrintf ( +"CAS: Request from %s => available=0x%x \tN=%d paddr=%x\n", + hostName, mp->m_available, mnum, (pciu?&pciu->addr:NULL)); + + if (mp->m_cmmd==CA_PROTO_WRITE && mp->m_type==DBF_STRING) { + epicsPrintf ( +"CAS: Request from %s => \tThe string written: %s \n", + hostName, (mp+1)); + } +} + +/* + * logBadIdWithFileAndLineno() + */ LOCAL void logBadIdWithFileAndLineno( struct client *client, caHdr *mp, char *pFileName, unsigned lineno -); +) +{ + log_header("bad resource ID", client, mp,0); + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "Bad Resource ID at %s.%d", + pFileName, + lineno); + SEND_UNLOCK(client); +} -#define logBadId(CLIENT, MP)\ -logBadIdWithFileAndLineno(CLIENT, MP, __FILE__, __LINE__) +/* + * bad_msg_action() + */ +LOCAL int bad_msg_action( +caHdr *mp, +struct client *client, +const char *pCtx +) +{ + log_header (pCtx, client, mp, 0); -LOCAL struct channel_in_use *MPTOPCIU( -caHdr *mp -); + /* + * by default, clients dont recover + * from this + */ + SEND_LOCK (client); + send_err (mp, ECA_INTERNAL, client, pCtx); + SEND_UNLOCK (client); -LOCAL void write_notify_call_back(PUTNOTIFY *ppn); + return ERROR; +} -LOCAL void write_notify_action( -caHdr *mp, -struct client *client -); - -LOCAL void putNotifyErrorReply( -struct client *client, -caHdr *mp, -int statusCA -); - -LOCAL void claim_ciu_action( -caHdr *mp, -struct client *client -); - -LOCAL void client_name_action( +/* + * bad_tcp_cmd_action() + */ +LOCAL int bad_tcp_cmd_action( caHdr *mp, struct client *client -); +) +{ + return bad_msg_action (mp, client, "bad (damaged?) TCP request id"); +} -LOCAL void host_name_action( +/* + * bad_udp_cmd_action() + */ +LOCAL int bad_udp_cmd_action( caHdr *mp, struct client *client -); +) +{ + return bad_msg_action (mp, client, "bad (damaged?) UDP request id"); +} -LOCAL void casAccessRightsCB( -ASCLIENTPVT ascpvt, -asClientStatus type -); +/* + * noop_action() + */ +LOCAL int noop_action( +caHdr *mp, +struct client *client +) +{ + return OK; +} +/* + * echo_action() + */ +LOCAL int echo_action( +caHdr *mp, +struct client *client +) +{ + caHdr *reply; + + SEND_LOCK(client); + reply = ALLOC_MSG(client, 0); + if (reply) { + /* + * header (host) will we converted in send, + * content is still in net format: + */ + *reply = *mp; + END_MSG(client); + } + SEND_UNLOCK(client); + + return OK; +} + +/* + * events_on_action () + */ +LOCAL int events_on_action ( +caHdr *mp, +struct client *client +) +{ + db_event_flow_ctrl_mode_off(client->evuser); + + return OK; +} + +/* + * events_off_action () + */ +LOCAL int events_off_action ( +caHdr *mp, +struct client *client +) +{ + db_event_flow_ctrl_mode_on(client->evuser); + + return OK; +} + +/* + * no_read_access_event() + * + * !! LOCK needs to applied by caller !! + * + * substantial complication introduced here by the need for backwards + * compatibility + */ LOCAL void no_read_access_event( struct client *client, struct event_ext *pevext -); - -LOCAL void access_rights_reply( -struct channel_in_use *pciu -); - -LOCAL struct channel_in_use *casCreateChannel ( -struct client *client, -struct dbAddr *pAddr, -unsigned cid -); - -LOCAL void *casCalloc (size_t count, size_t size); - -LOCAL void *casMalloc (size_t size); - -LOCAL unsigned nextRsrvResourceID; - - -/* - * CAMESSAGE() - */ -int camessage( -struct client *client, -struct message_buffer *recv ) { - unsigned long tmp_postsize; - int nmsg = 0; - int v41; - unsigned long msgsize; - unsigned long bytes_left; - int status; - caHdr *mp; - struct channel_in_use *pciu; + caHdr *reply; + int v41; - if(!pCaBucket){ - pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE); - if(!pCaBucket){ - return ERROR; - } - } + v41 = CA_V41(CA_PROTOCOL_VERSION,client->minor_version_number); - DLOG (2, "CAS: Parsing %d(decimal) bytes\n", - recv->cnt, NULL, NULL, NULL, NULL, NULL); - - bytes_left = recv->cnt; - while (bytes_left) - { - - /* assert that we have at least a complete caHdr */ - if(bytes_left < sizeof(*mp)) - return OK; - - mp = (caHdr *) &recv->buf[recv->stk]; - - /* problem: we have a complete header, - * but before we check msgsize we don't know - * if we have a complete message body - * -> we may be called again with the same header - * after receiving the full message - */ - tmp_postsize = ntohs (mp->m_postsize); - msgsize = tmp_postsize + sizeof(*mp); - - if(msgsize > bytes_left) - return OK; - - /* Have complete message (header + content) - * -> convert the header elements - */ - mp->m_cmmd = ntohs (mp->m_cmmd); - mp->m_postsize = tmp_postsize; - mp->m_type = ntohs (mp->m_type); - mp->m_count = ntohs (mp->m_count); - mp->m_cid = ntohl (mp->m_cid); - mp->m_available = ntohl (mp->m_available); - - nmsg++; - - if (CASDEBUG > 2) - log_header(mp, nmsg); - - switch (mp->m_cmmd) { - case CA_PROTO_NOOP: /* verify TCP */ - break; - - case CA_PROTO_ECHO: /* verify TCP */ - { - caHdr *reply; - - SEND_LOCK(client); - reply = ALLOC_MSG(client, 0); - assert (reply); - /* - * header (host) will we converted in send, - * content is still in net format: - */ - *reply = *mp; - END_MSG(client); - SEND_UNLOCK(client); - break; - } - case CA_PROTO_CLIENT_NAME: - client_name_action(mp, client); - break; - - case CA_PROTO_HOST_NAME: - host_name_action(mp, client); - break; - - case CA_PROTO_EVENT_ADD: - event_add_action(mp, client); - break; - - case CA_PROTO_EVENT_CANCEL: - event_cancel_reply(mp, client); - break; - - case CA_PROTO_CLEAR_CHANNEL: - clear_channel_reply(mp, client); - break; - - case CA_PROTO_READ_NOTIFY: - case CA_PROTO_READ: - { - struct event_ext evext; - - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - break; - } - - evext.msg = *mp; - evext.pciu = pciu; - evext.send_lock = TRUE; - evext.pdbev = NULL; - evext.size = dbr_size_n(mp->m_type, mp->m_count); - - /* - * Arguments to this routine organized in - * favor of the standard db event calling - * mechanism- routine(userarg, paddr). See - * events added above. - * - * Hold argument set true so the send message - * buffer is not flushed once each call. - */ - read_reply(&evext, &pciu->addr, TRUE, NULL); - break; - } - case CA_PROTO_SEARCH: - search_reply(mp, client); - break; - - case CA_PROTO_WRITE_NOTIFY: - write_notify_action(mp, client); - break; - - case CA_PROTO_WRITE: - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - break; - } - if(!asCheckPut(pciu->asClientPVT)){ - v41 = CA_V41( - CA_PROTOCOL_VERSION, - client->minor_version_number); - if(v41){ - status = ECA_NOWTACCESS; - } - else{ - status = ECA_PUTFAIL; - } - SEND_LOCK(client); - send_err( - mp, - status, - client, - RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - break; - } - -#ifdef CONVERSION_REQUIRED - if (mp->m_type >= NELEMENTS(cac_dbr_cvrt)) { - SEND_LOCK(client); - send_err( - mp, - ECA_PUTFAIL, - client, - RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - break; - } - - /* use type as index into conversion jumptable */ - (* cac_dbr_cvrt[mp->m_type]) - ( mp + 1, - mp + 1, - FALSE, /* net -> host format */ - mp->m_count); -#endif - status = db_put_field( - &pciu->addr, - mp->m_type, - mp + 1, - mp->m_count); - if (status < 0) { - SEND_LOCK(client); - send_err( - mp, - ECA_PUTFAIL, - client, - RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - } - break; - - case CA_PROTO_EVENTS_ON: - db_event_flow_ctrl_mode_off(client->evuser); - break; - - case CA_PROTO_EVENTS_OFF: - db_event_flow_ctrl_mode_on(client->evuser); - break; - - case CA_PROTO_READ_SYNC: - read_sync_reply(mp, client); - break; - - case CA_PROTO_CLAIM_CIU: - claim_ciu_action(mp, client); - break; - - case CA_PROTO_READ_BUILD: - case CA_PROTO_BUILD: - /* - * starting with 3.12 CA ignores this - * protocol. No message is sent so that we avoid - * a broadcast storm. - */ - break; - - default: - logMsg("CAS: bad msg detected\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - log_header(mp, nmsg); - /* - * most clients dont recover - * from this - */ - SEND_LOCK(client); - send_err(mp, ECA_INTERNAL, client, "Invalid Msg"); - SEND_UNLOCK(client); - /* - * returning ERROR here disconnects - * the client with the bad message - */ - logMsg("CAS: forcing disconnect ...\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - logMsg("recv->stk: %d, bytes_left: %d\n", - (int) recv->stk, (int) bytes_left, - 0, 0, 0, 0); - return ERROR; - } - - recv->stk += msgsize; - bytes_left = recv->cnt - recv->stk; - } - - return OK; -} - - -/* - * host_name_action() - */ -LOCAL void host_name_action( -caHdr *mp, -struct client *client -) -{ - struct channel_in_use *pciu; - unsigned size; - char *pName; - char *pMalloc; - int status; - - pName = (char *)(mp+1); - size = strlen(pName)+1; /* - * user name will not change if there isnt enough memory + * continue to return an exception + * on failure to pre v41 clients */ - pMalloc = malloc(size); - if(!pMalloc){ + if(!v41){ send_err( - mp, - ECA_ALLOCMEM, - client, - ""); + &pevext->msg, + ECA_GETFAIL, + client, + RECORD_NAME(&pevext->pciu->addr)); return; } - strncpy( - pMalloc, - pName, - size-1); - pMalloc[size-1]='\0'; - FASTLOCK(&client->addrqLock); - pName = client->pHostName; - client->pHostName = pMalloc; - if(pName){ - free(pName); - } - - pciu = (struct channel_in_use *) client->addrq.node.next; - while(pciu){ - status = asChangeClient( - pciu->asClientPVT, - asDbGetAsl(&pciu->addr), - client->pUserName, - client->pHostName); - if(status != 0 && status != S_asLib_asNotActive){ - FASTUNLOCK(&client->addrqLock); - free_client(client); - exit(0); - } - pciu = (struct channel_in_use *) pciu->node.next; - } - FASTUNLOCK(&client->addrqLock); - - DLOG(2, "CAS: host_name_action for \"%s\"\n", - (int) client->pHostName, - NULL, NULL, NULL, NULL, NULL); -} - - -/* - * client_name_action() - */ -LOCAL void client_name_action( -caHdr *mp, -struct client *client -) -{ - struct channel_in_use *pciu; - unsigned size; - char *pName; - char *pMalloc; - int status; - - pName = (char *)(mp+1); - size = strlen(pName)+1; - /* - * user name will not change if there isnt enough memory - */ - pMalloc = malloc(size); - if(!pMalloc){ + reply = (caHdr *) ALLOC_MSG(client, pevext->size); + if (!reply) { send_err( - mp, - ECA_ALLOCMEM, - client, - ""); + &pevext->msg, + ECA_TOLARGE, + client, + RECORD_NAME(&pevext->pciu->addr)); return; } - strncpy( - pMalloc, - pName, - size-1); - pMalloc[size-1]='\0'; - - FASTLOCK(&client->addrqLock); - pName = client->pUserName; - client->pUserName = pMalloc; - if(pName){ - free(pName); - } - - pciu = (struct channel_in_use *) client->addrq.node.next; - while(pciu){ - status = asChangeClient( - pciu->asClientPVT, - asDbGetAsl(&pciu->addr), - client->pUserName, - client->pHostName); - if(status != 0 && status != S_asLib_asNotActive){ - FASTUNLOCK(&client->addrqLock); - free_client(client); - exit(0); - } - pciu = (struct channel_in_use *) pciu->node.next; - } - FASTUNLOCK(&client->addrqLock); - - DLOG (2, "CAS: client_name_action for \"%s\"\n", - (int) client->pUserName, - NULL, NULL, NULL, NULL, NULL); -} - - -/* - * claim_ciu_action() - */ -LOCAL void claim_ciu_action( -caHdr *mp, -struct client *client -) -{ - int v42; - int status; - struct channel_in_use *pciu; - - /* - * The available field is used (abused) - * here to communicate the miner version number - * starting with CA 4.1. The field was set to zero - * prior to 4.1 - */ - client->minor_version_number = mp->m_available; - - if (CA_V44(CA_PROTOCOL_VERSION,client->minor_version_number)) { - struct dbAddr tmp_addr; - - status = db_name_to_addr( - (char *)(mp+1), - &tmp_addr); - if (status < 0) { - return; - } - - DLOG(2,"CAS: claim_ciu_action found '%s', type %d, count %d\n", - (int) (mp+1), - tmp_addr.dbr_field_type, - tmp_addr.no_elements, - NULL, NULL, NULL); - - pciu = casCreateChannel ( - client, - &tmp_addr, - mp->m_cid); - if (!pciu) { - SEND_LOCK(client); - send_err(mp, - ECA_ALLOCMEM, - client, - RECORD_NAME(&tmp_addr)); - SEND_UNLOCK(client); - return; - } - } - else { - FASTLOCK(&prsrv_cast_client->addrqLock); - /* - * clients which dont claim their - * channel in use block prior to - * timeout must reconnect - */ - pciu = MPTOPCIU(mp); - if(!pciu){ - logMsg("CAS: client timeout disconnect id=%d\n", - mp->m_cid, - NULL, - NULL, - NULL, - NULL, - NULL); - FASTUNLOCK(&prsrv_cast_client->addrqLock); - free_client(client); - exit(0); - } - - /* - * duplicate claim message are unacceptable - * (so we disconnect the client) - */ - if (pciu->client!=prsrv_cast_client) { - logMsg("CAS: double claim disconnect id=%d\n", - mp->m_cid, - NULL, - NULL, - NULL, - NULL, - NULL); - FASTUNLOCK(&prsrv_cast_client->addrqLock); - free_client(client); - exit(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( - &prsrv_cast_client->addrq, - &pciu->node); - FASTUNLOCK(&prsrv_cast_client->addrqLock); - - FASTLOCK(&prsrv_cast_client->addrqLock); - pciu->client = client; - ellAdd(&client->addrq, &pciu->node); - FASTUNLOCK(&prsrv_cast_client->addrqLock); - } - - - /* - * set up access security for this channel - */ - status = asAddClient( - &pciu->asClientPVT, - asDbGetMemberPvt(&pciu->addr), - asDbGetAsl(&pciu->addr), - client->pUserName, - client->pHostName); - if(status != 0 && status != S_asLib_asNotActive){ - SEND_LOCK(client); - send_err(mp, ECA_ALLOCMEM, client, "No room for security table"); - SEND_UNLOCK(client); - free_client(client); - exit(0); - } - - /* - * store ptr to channel in use block - * in access security private - */ - asPutClientPvt(pciu->asClientPVT, pciu); - - v42 = CA_V42( - CA_PROTOCOL_VERSION, - client->minor_version_number); - - /* - * register for asynch updates of access rights changes - * (only after the lock is released, we are added to - * the correct client, and the clients version is - * known) - */ - status = asRegisterClientCallback( - pciu->asClientPVT, - casAccessRightsCB); - if(status == S_asLib_asNotActive){ - /* - * force the initial update - */ - access_rights_reply(pciu); - } else{ - assert(status==0); - } - - if(v42){ - caHdr *claim_reply; - - SEND_LOCK(client); - claim_reply = (caHdr *) ALLOC_MSG(client, 0); - assert (claim_reply); - - *claim_reply = nill_msg; - claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU; - claim_reply->m_type = pciu->addr.dbr_field_type; - claim_reply->m_count = pciu->addr.no_elements; - claim_reply->m_cid = pciu->cid; - claim_reply->m_available = pciu->sid; - - DBLOCK(3, - printf ("claim_cui reply:\n"); - log_header (claim_reply, 0); - ) - + /* + * New clients recv the status of the + * operation directly to the + * event/put/get callback. + * + * Fetched value is zerod in case they + * use it even when the status indicates + * failure. + * + * The m_cid field in the protocol + * header is abused to carry the status + */ + *reply = pevext->msg; + reply->m_postsize = pevext->size; + reply->m_cid = ECA_NORDACCESS; + bzero((char *)(reply+1), pevext->size); END_MSG(client); - SEND_UNLOCK(client); } } - /* - * write_notify_call_back() - * - * (called by the db call back thread) - */ -LOCAL void write_notify_call_back(PUTNOTIFY *ppn) -{ - struct client *pclient; - struct channel_in_use *pciu; - - /* - * we choose to suspend the task if there - * is an internal failure - */ - pciu = (struct channel_in_use *) ppn->usrPvt; - assert(pciu); - assert(pciu->pPutNotify); - - if(!pciu->pPutNotify->busy){ - logMsg("Double DB put notify call back!!\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - return; - } - - pclient = pciu->client; - - /* - * independent lock used here in order to - * avoid any possibility of blocking - * the database (or indirectly blocking - * one client on another client). - */ - FASTLOCK(&pclient->putNotifyLock); - ellAdd(&pclient->putNotifyQue, &pciu->pPutNotify->node); - FASTUNLOCK(&pclient->putNotifyLock); - - /* - * offload the labor for this to the - * event task so that we never block - * the db or another client. - */ - db_post_extra_labor(pclient->evuser); -} - - -/* - * write_notify_reply() - * - * (called by the CA server event task via the extra labor interface) - */ -void write_notify_reply(void *pArg) -{ - RSRVPUTNOTIFY *ppnb; - struct client *pClient; - caHdr *preply; - int status; - - pClient = pArg; - - SEND_LOCK(pClient); - while(TRUE){ - /* - * independent lock used here in order to - * avoid any possibility of blocking - * the database (or indirectly blocking - * one client on another client). - */ - FASTLOCK(&pClient->putNotifyLock); - ppnb = (RSRVPUTNOTIFY *)ellGet(&pClient->putNotifyQue); - FASTUNLOCK(&pClient->putNotifyLock); - /* - * break to loop exit - */ - if(!ppnb){ - break; - } - - /* - * aquire sufficient output buffer - */ - preply = ALLOC_MSG(pClient, 0); - if (!preply) { - /* - * inability to aquire buffer space - * Indicates corruption - */ - logMsg("CA server corrupted - put call back(s) discarded\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - break; - } - *preply = ppnb->msg; - /* - * - * Map from DB status to CA status - * - * the channel id field is being abused to carry - * status here - */ - if(ppnb->dbPutNotify.status){ - if(ppnb->dbPutNotify.status == S_db_Blocked){ - preply->m_cid = ECA_PUTCBINPROG; - } - else{ - preply->m_cid = ECA_PUTFAIL; - } - } - else{ - preply->m_cid = ECA_NORMAL; - } - - /* commit the message */ - END_MSG(pClient); - ppnb->busy = FALSE; - } - - cas_send_msg(pClient,FALSE); - - SEND_UNLOCK(pClient); - - /* - * wakeup the TCP thread if it is waiting for a cb to complete - */ - status = semGive(pClient->blockSem); - if(status != OK){ - logMsg("CA block sem corrupted\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - } -} - - -/* - * write_notify_action() - */ -LOCAL void write_notify_action( -caHdr *mp, -struct client *client -) -{ - unsigned long size; - int status; - struct channel_in_use *pciu; - - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - return; - } - - if (mp->m_type > LAST_BUFFER_TYPE) { - putNotifyErrorReply(client, mp, ECA_BADTYPE); - return; - } - - if(!asCheckPut(pciu->asClientPVT)){ - putNotifyErrorReply(client, mp, ECA_NOWTACCESS); - return; - } - - size = dbr_size_n(mp->m_type, mp->m_count); - - if(pciu->pPutNotify){ - /* - * serialize concurrent put notifies - */ - while(pciu->pPutNotify->busy){ - status = semTake( - client->blockSem, - sysClkRateGet()*60); - if(status != OK && pciu->pPutNotify->busy){ - log_header(mp,0); - dbNotifyCancel(&pciu->pPutNotify->dbPutNotify); - pciu->pPutNotify->busy = FALSE; - putNotifyErrorReply( - client, - mp, - ECA_PUTCBINPROG); - return; - } - } - - /* - * if not busy then free the current - * block if it is to small - */ - if(pciu->pPutNotify->valueSizepPutNotify); - pciu->pPutNotify = NULL; - } - } - - /* - * send error and go to next request - * if there isnt enough memory left - */ - if(!pciu->pPutNotify){ - pciu->pPutNotify = (RSRVPUTNOTIFY *) - casCalloc(1, sizeof(*pciu->pPutNotify)+size); - if(!pciu->pPutNotify){ - putNotifyErrorReply(client, mp, ECA_ALLOCMEM); - return; - } - pciu->pPutNotify->valueSize = size; - pciu->pPutNotify->dbPutNotify.pbuffer = (pciu->pPutNotify+1); - pciu->pPutNotify->dbPutNotify.usrPvt = pciu; - pciu->pPutNotify->dbPutNotify.paddr = &pciu->addr; - pciu->pPutNotify->dbPutNotify.userCallback = write_notify_call_back; - } - - pciu->pPutNotify->busy = TRUE; - pciu->pPutNotify->msg = *mp; - pciu->pPutNotify->dbPutNotify.nRequest = mp->m_count; -#ifdef CONVERSION_REQUIRED - /* use type as index into conversion jumptable */ - (* cac_dbr_cvrt[mp->m_type]) - ( mp + 1, - pciu->pPutNotify->dbPutNotify.pbuffer, - FALSE, /* net -> host format */ - mp->m_count); -#else - memcpy(pciu->pPutNotify->dbPutNotify.pbuffer, (char *)(mp+1), size); -#endif - status = dbPutNotifyMapType(&pciu->pPutNotify->dbPutNotify, mp->m_type); - if(status){ - putNotifyErrorReply(client, mp, ECA_PUTFAIL); - pciu->pPutNotify->busy = FALSE; - return; - } - - status = dbPutNotify(&pciu->pPutNotify->dbPutNotify); - if(status && status != S_db_Pending){ - /* - * let the call back take care of failure - * even if it is immediate - */ - pciu->pPutNotify->dbPutNotify.status = status; - (*pciu->pPutNotify->dbPutNotify.userCallback) - (&pciu->pPutNotify->dbPutNotify); - } -} - - -/* - * putNotifyErrorReply - */ -LOCAL void putNotifyErrorReply(struct client *client, caHdr *mp, int statusCA) -{ - caHdr *preply; - - SEND_LOCK(client); - preply = ALLOC_MSG(client, 0); - if(!preply){ - logMsg("Fatal Error:%s, %d\n", - (int)__FILE__, - __LINE__, - NULL, - NULL, - NULL, - NULL); - taskSuspend(0); - } - - *preply = *mp; - /* - * the cid field abused to contain status - * during put cb replies - */ - preply->m_cid = statusCA; - END_MSG(client); - SEND_UNLOCK(client); -} - - -/* - * - * event_add_action() - * - */ -LOCAL void event_add_action( -caHdr *mp, -struct client *client -) -{ - struct monops *pmo = (struct monops *) mp; - struct channel_in_use *pciu; - struct event_ext *pevext; - int status; - int size; - - if (client==prsrv_cast_client) { - printf("cas: add event from UDP???\n"); - return; - } - - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - return; - } - - pevext = (struct event_ext *) freeListMalloc(rsrvEventFreeList); - size = db_sizeof_event_block() + sizeof(*pevext); - if (!pevext) { - SEND_LOCK(client); - send_err( - mp, - ECA_ALLOCMEM, - client, - RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - return; - } - -#ifdef CONVERSION_REQUIRED - - /* I convert here is the full message that we get, - * though only m_mask seems to be used - */ - dbr_ntohf (&pmo->m_info.m_lval , &pmo->m_info.m_lval); - dbr_ntohf (&pmo->m_info.m_hval , &pmo->m_info.m_hval); - dbr_ntohf (&pmo->m_info.m_toval, &pmo->m_info.m_toval); - pmo->m_info.m_mask = ntohs (pmo->m_info.m_mask); -#endif - - memset(pevext,0,size); - pevext->msg = *mp; - pevext->pciu = pciu; - pevext->send_lock = TRUE; - pevext->size = dbr_size_n(mp->m_type, mp->m_count); - pevext->mask = pmo->m_info.m_mask; - - FASTLOCK(&client->eventqLock); - ellAdd( &pciu->eventq, &pevext->node); - FASTUNLOCK(&client->eventqLock); - - pevext->pdbev = (struct event_block *)(pevext+1); - - status = db_add_event( - client->evuser, - &pciu->addr, - read_reply, - pevext, - pevext->mask, - pevext->pdbev); - if (status == ERROR) { - pevext->pdbev = NULL; - SEND_LOCK(client); - send_err( - mp, - ECA_ADDFAIL, - client, - RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - return; - } - - /* - * always send it once at event add - */ - /* - * if the client program issues many monitors - * in a row then I recv when the send side - * of the socket would block. This prevents - * a application program initiated deadlock. - * - * However when I am reconnecting I reissue - * the monitors and I could get deadlocked. - * The client is blocked sending and the server - * task for the client is blocked sending in - * this case. I cant check the recv part of the - * socket in the client since I am still handling an - * outstanding recv ( they must be processed in order). - * I handle this problem in the server by using - * post_single_event() below instead of calling - * read_reply() in this module. This is a complete - * fix since a monitor setup is the only request - * soliciting a reply in the client which is - * issued from inside of service.c (from inside - * of the part of the ca client which services - * messages sent by the server). - */ - - DLOG(3, "event_add_action: db_post_single_event (0x%X)\n", - (int) pevext->pdbev, 0, 0, 0, 0, 0); - db_post_single_event(pevext->pdbev); - - /* - * disable future labor if no read access - */ - if(!asCheckGet(pciu->asClientPVT)){ - db_event_disable(pevext->pdbev); - DLOG(3, "Disable event because cannot read\n", - 0, 0, 0, 0, 0, 0); - } - - return; -} - - - -/* - * - * clear_channel_reply() - * - * - */ -LOCAL void clear_channel_reply( -caHdr *mp, -struct client *client -) -{ - caHdr *reply; - struct event_ext *pevext; - struct channel_in_use *pciu; - int status; - - /* - * - * Verify the channel - * - */ - pciu = MPTOPCIU(mp); - if(pciu?pciu->client!=client:TRUE){ - logBadId(client, mp); - return; - } - - /* - * if a put notify is outstanding then cancel it - */ - if(pciu->pPutNotify){ - if(pciu->pPutNotify->busy){ - dbNotifyCancel(&pciu->pPutNotify->dbPutNotify); - } - } - - while (TRUE){ - FASTLOCK(&client->eventqLock); - pevext = (struct event_ext *) ellGet(&pciu->eventq); - FASTUNLOCK(&client->eventqLock); - - if(!pevext){ - break; - } - - if(pevext->pdbev){ - status = db_cancel_event(pevext->pdbev); - assert(status == OK); - } - freeListFree(rsrvEventFreeList, pevext); - } - - status = db_flush_extra_labor_event(client->evuser); - if(status){ - taskSuspend(0); - } - - if (pciu->pPutNotify) { - free (pciu->pPutNotify); - } - - /* - * send delete confirmed message - */ - SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, 0); - if (!reply) { - SEND_UNLOCK(client); - taskSuspend(0); - } - *reply = *mp; - - END_MSG(client); - SEND_UNLOCK(client); - - FASTLOCK(&client->addrqLock); - ellDelete(&client->addrq, &pciu->node); - FASTUNLOCK(&client->addrqLock); - - /* - * remove from access control list - */ - status = asRemoveClient(&pciu->asClientPVT); - assert(status == 0 || status == S_asLib_asNotActive); - if(status != 0 && status != S_asLib_asNotActive){ - errMessage(status, RECORD_NAME(&pciu->addr)); - } - - FASTLOCK(&clientQlock); - status = bucketRemoveItemUnsignedId (pCaBucket, &pciu->sid); - if(status != S_bucket_success){ - errMessage (status, "Bad resource id during channel clear"); - logBadId(client, mp); - } - FASTUNLOCK(&clientQlock); - freeListFree(rsrvChanFreeList, pciu); - - return; -} - - - - -/* - * - * event_cancel_reply() - * - * - * Much more efficient now since the event blocks hang off the channel in use - * blocks not all together off the client block. - */ -LOCAL void event_cancel_reply( -caHdr *mp, -struct client *client -) -{ - struct channel_in_use *pciu; - caHdr *reply; - struct event_ext *pevext; - int status; - - /* - * - * Verify the channel - * - */ - pciu = MPTOPCIU(mp); - if(pciu?pciu->client!=client:TRUE){ - logBadId(client, mp); - return; - } - - /* - * search events on this channel for a match - * (there are usually very few monitors per channel) - */ - FASTLOCK(&client->eventqLock); - for (pevext = (struct event_ext *) ellFirst(&pciu->eventq); - pevext; - pevext = (struct event_ext *) ellNext(&pevext->node)){ - - if (pevext->msg.m_available == mp->m_available) { - ellDelete(&pciu->eventq, &pevext->node); - break; - } - } - FASTUNLOCK(&client->eventqLock); - - /* - * Not Found- return an exception event - */ - if(!pevext){ - SEND_LOCK(client); - send_err(mp, ECA_BADMONID, client, RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - return; - } - - - /* - * cancel monitor activity in progress - */ - if(pevext->pdbev){ - status = db_cancel_event(pevext->pdbev); - assert(status == OK); - } - - /* - * send delete confirmed message - */ - SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, 0); - if (!reply) { - SEND_UNLOCK(client); - assert(0); - } - *reply = pevext->msg; - reply->m_postsize = 0; - - END_MSG(client); - SEND_UNLOCK(client); - - freeListFree (rsrvEventFreeList, pevext); -} - - - -/* - * * read_reply() - * - * */ LOCAL void read_reply( void *pArg, @@ -1530,215 +639,286 @@ db_field_log *pfl return; } - /* - * no_read_access_event() - * - * !! LOCK needs to applied by caller !! - * - * substantial complication introduced here by the need for backwards - * compatibility + * read_action() */ -LOCAL void no_read_access_event( -struct client *client, -struct event_ext *pevext +LOCAL int read_action( +caHdr *mp, +struct client *client ) { - caHdr *reply; - int v41; + struct channel_in_use *pciu; + struct event_ext evext; - v41 = CA_V41(CA_PROTOCOL_VERSION,client->minor_version_number); + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return ERROR; + } + + evext.msg = *mp; + evext.pciu = pciu; + evext.send_lock = TRUE; + evext.pdbev = NULL; + evext.size = dbr_size_n(mp->m_type, mp->m_count); /* - * continue to return an exception - * on failure to pre v41 clients + * Arguments to this routine organized in + * favor of the standard db event calling + * mechanism- routine(userarg, paddr). See + * events added above. + * + * Hold argument set true so the send message + * buffer is not flushed once each call. */ - if(!v41){ - send_err( - &pevext->msg, - ECA_GETFAIL, - client, - RECORD_NAME(&pevext->pciu->addr)); - return; - } + read_reply(&evext, &pciu->addr, TRUE, NULL); - reply = (caHdr *) ALLOC_MSG(client, pevext->size); - if (!reply) { - send_err( - &pevext->msg, - ECA_TOLARGE, - client, - RECORD_NAME(&pevext->pciu->addr)); - return; - } - else{ - /* - * New clients recv the status of the - * operation directly to the - * event/put/get callback. - * - * Fetched value is zerod in case they - * use it even when the status indicates - * failure. - * - * The m_cid field in the protocol - * header is abused to carry the status - */ - *reply = pevext->msg; - reply->m_postsize = pevext->size; - reply->m_cid = ECA_NORDACCESS; - bzero((char *)(reply+1), pevext->size); - END_MSG(client); - } + return OK; } - /* - * - * read_sync_reply() - * - * + * write_action() */ -LOCAL void read_sync_reply( -caHdr *mp, -struct client *client +LOCAL int write_action( +caHdr *mp, +struct client *client ) { - FAST caHdr *reply; + struct channel_in_use *pciu; + int v41; + long status; - SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, 0); - if (!reply) - taskSuspend(0); - - *reply = *mp; - - END_MSG(client); - - SEND_UNLOCK(client); - - return; -} - - -/* - * - * search_reply() - * - * - */ -LOCAL void search_reply( -caHdr *mp, -struct client *client -) -{ - struct dbAddr tmp_addr; - caHdr *search_reply; - unsigned short *pMinorVersion; - int status; - unsigned sid; - unsigned long count; - ca_uint16_t type; - int spaceAvailOnFreeList; - - /* Exit quickly if channel not on this node */ - status = db_name_to_addr( - (char *) (mp+1), - &tmp_addr); - if (status < 0) { - DLOG (2, "CAS: Lookup for channel \"%s\" failed\n", - (int)(mp+1), - NULL, - NULL, - NULL, - NULL, - NULL); - if (mp->m_type == DOREPLY) - search_fail_reply(mp, client); - return; + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return ERROR; } - /* - * stop further use of server if max block drops - * below MAX_BLOCK_THRESHOLD - */ - spaceAvailOnFreeList = freeListItemsAvail(rsrvClientFreeList)>0 - && freeListItemsAvail(rsrvChanFreeList)>0 - && freeListItemsAvail(rsrvEventFreeList)>0; - if (casBelowMaxBlockThresh && !spaceAvailOnFreeList) { - SEND_LOCK(client); - send_err(mp, - ECA_ALLOCMEM, - client, - "Server memory exhausted"); - SEND_UNLOCK(client); - return; - } - - /* - * starting with V4.4 the count field is used (abused) - * to store the minor version number of the client. - * - * New versions dont alloc the channel in response - * to a search request. - * - * m_count, m_cid are already in host format... - */ - if (CA_V44(CA_PROTOCOL_VERSION, mp->m_count)) { - sid = ~0U; - count = 0; - type = ca_server_port; - } - else { - struct channel_in_use *pchannel; - - pchannel = casCreateChannel ( - client, - &tmp_addr, - mp->m_cid); - if (!pchannel) { - SEND_LOCK(client); - send_err(mp, - ECA_ALLOCMEM, - client, - RECORD_NAME(&tmp_addr)); - SEND_UNLOCK(client); - return; + if(!asCheckPut(pciu->asClientPVT)){ + v41 = CA_V41( + CA_PROTOCOL_VERSION, + client->minor_version_number); + if(v41){ + status = ECA_NOWTACCESS; } - sid = pchannel->sid; - count = tmp_addr.no_elements; - type = (ca_uint16_t) tmp_addr.dbr_field_type; + else{ + status = ECA_PUTFAIL; + } + SEND_LOCK(client); + send_err( + mp, + status, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return OK; } - SEND_LOCK(client); + if (mp->m_type >= NELEMENTS(cac_dbr_cvrt)) { + SEND_LOCK(client); + send_err( + mp, + ECA_PUTFAIL, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return ERROR; + } - search_reply = (caHdr *) - ALLOC_MSG(client, sizeof(*pMinorVersion)); - assert (search_reply); +#ifdef CONVERSION_REQUIRED + /* use type as index into conversion jumptable */ + (* cac_dbr_cvrt[mp->m_type]) + ( mp + 1, + mp + 1, + FALSE, /* net -> host format */ + mp->m_count); +#endif - *search_reply = *mp; - search_reply->m_postsize = sizeof(*pMinorVersion); - - /* this field for rmt machines where paddr invalid */ - search_reply->m_type = type; - search_reply->m_count = count; - search_reply->m_cid = sid; - - /* - * Starting with CA V4.1 the minor version number - * is appended to the end of each search reply. - * This value is ignored by earlier clients. - */ - pMinorVersion = (unsigned short *)(search_reply+1); - *pMinorVersion = htons(CA_MINOR_VERSION); - - END_MSG(client); - SEND_UNLOCK(client); - - return; + status = db_put_field( + &pciu->addr, + mp->m_type, + mp + 1, + mp->m_count); + if (status < 0) { + SEND_LOCK(client); + send_err( + mp, + ECA_PUTFAIL, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + } + return OK; } +/* + * host_name_action() + */ +LOCAL int host_name_action( +caHdr *mp, +struct client *client +) +{ + struct channel_in_use *pciu; + unsigned size; + char *pName; + char *pMalloc; + int status; + + pName = (char *)(mp+1); + size = strlen(pName)+1; + if (size > 512) { + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "bad (very long) host name"); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * user name will not change if there isnt enough memory + */ + pMalloc = malloc(size); + if(!pMalloc){ + SEND_LOCK(client); + send_err( + mp, + ECA_ALLOCMEM, + client, + "no room for new host name"); + SEND_UNLOCK(client); + return ERROR; + } + strncpy( + pMalloc, + pName, + size-1); + pMalloc[size-1]='\0'; + + FASTLOCK(&client->addrqLock); + pName = client->pHostName; + client->pHostName = pMalloc; + if(pName){ + free(pName); + } + + pciu = (struct channel_in_use *) client->addrq.node.next; + while(pciu){ + status = asChangeClient( + pciu->asClientPVT, + asDbGetAsl(&pciu->addr), + client->pUserName, + client->pHostName); + if(status != 0 && status != S_asLib_asNotActive){ + FASTUNLOCK(&client->addrqLock); + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "unable to install new host name into access security"); + SEND_UNLOCK(client); + return ERROR; + } + pciu = (struct channel_in_use *) pciu->node.next; + } + FASTUNLOCK(&client->addrqLock); + + DLOG(2, "CAS: host_name_action for \"%s\"\n", + (int) client->pHostName, + NULL, NULL, NULL, NULL, NULL); + + return OK; +} + + +/* + * client_name_action() + */ +LOCAL int client_name_action( +caHdr *mp, +struct client *client +) +{ + struct channel_in_use *pciu; + unsigned size; + char *pName; + char *pMalloc; + int status; + + pName = (char *)(mp+1); + size = strlen(pName)+1; + if (size > 512) { + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "very long user name"); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * user name will not change if there isnt enough memory + */ + pMalloc = malloc(size); + if(!pMalloc){ + SEND_LOCK(client); + send_err( + mp, + ECA_ALLOCMEM, + client, + "no memory for new user name"); + SEND_UNLOCK(client); + return ERROR; + } + strncpy( + pMalloc, + pName, + size-1); + pMalloc[size-1]='\0'; + + FASTLOCK(&client->addrqLock); + pName = client->pUserName; + client->pUserName = pMalloc; + if(pName){ + free(pName); + } + + pciu = (struct channel_in_use *) client->addrq.node.next; + while(pciu){ + status = asChangeClient( + pciu->asClientPVT, + asDbGetAsl(&pciu->addr), + client->pUserName, + client->pHostName); + if(status != 0 && status != S_asLib_asNotActive){ + FASTUNLOCK(&client->addrqLock); + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "unable to install new user name into access security"); + SEND_UNLOCK(client); + return ERROR; + } + pciu = (struct channel_in_use *) pciu->node.next; + } + FASTUNLOCK(&client->addrqLock); + + DLOG (2, "CAS: client_name_action for \"%s\"\n", + (int) client->pUserName, + NULL, NULL, NULL, NULL, NULL); + + return OK; +} + /* * casCreateChannel () */ @@ -1748,6 +928,7 @@ struct dbAddr *pAddr, unsigned cid ) { + static unsigned bucketID; unsigned *pCID; struct channel_in_use *pchannel; int status; @@ -1784,7 +965,7 @@ unsigned cid * bypass read only warning */ pCID = (unsigned *) &pchannel->sid; - *pCID = nextRsrvResourceID++; + *pCID = bucketID++; /* * Verify that this id is not in use @@ -1810,269 +991,48 @@ unsigned cid return pchannel; } - -/* search_fail_reply() - * - * Only when requested by the client - * send search failed reply - * - * +/* + * access_rights_reply() */ -LOCAL void search_fail_reply( -caHdr *mp, -struct client *client -) +LOCAL void access_rights_reply(struct channel_in_use *pciu) { - FAST caHdr *reply; + struct client *pclient; + caHdr *reply; + unsigned ar; + int v41; - SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, 0); - if (!reply) { - taskSuspend(0); - } - *reply = *mp; - reply->m_cmmd = CA_PROTO_NOT_FOUND; - reply->m_postsize = 0; + pclient = pciu->client; - END_MSG(client); - SEND_UNLOCK(client); - -} - - -/* send_err() - * - * reflect error msg back to the client - * - * send buffer lock must be on while in this routine - * - */ -LOCAL void send_err( -caHdr *curp, -int status, -struct client *client, -char *pformat, - ... -) -{ - va_list args; - struct channel_in_use *pciu; - int size; - caHdr *reply; - char *pMsgString; - - va_start(args, pformat); + assert(pclient != prsrv_cast_client); /* - * allocate plenty of space for a sprintf() buffer + * noop if this is an old client */ - reply = (caHdr *) ALLOC_MSG(client, 512); - if (!reply){ - int logMsgArgs[6]; - size_t i; - - for(i=0; i< NELEMENTS(logMsgArgs); i++){ - logMsgArgs[i] = va_arg(args, int); - } - - logMsg( "caserver: Unable to deliver err msg to client => \"%s\"\n", - (int) ca_message(status), - NULL, - NULL, - NULL, - NULL, - NULL); - logMsg( - pformat, - logMsgArgs[0], - logMsgArgs[1], - logMsgArgs[2], - logMsgArgs[3], - logMsgArgs[4], - logMsgArgs[5]); - + v41 = CA_V41(CA_PROTOCOL_VERSION,pclient->minor_version_number); + if(!v41){ return; } - reply[0] = nill_msg; - reply[0].m_cmmd = CA_PROTO_ERROR; - reply[0].m_available = status; - - switch (curp->m_cmmd) { - case CA_PROTO_EVENT_ADD: - case CA_PROTO_EVENT_CANCEL: - case CA_PROTO_READ: - case CA_PROTO_READ_NOTIFY: - case CA_PROTO_WRITE: - case CA_PROTO_WRITE_NOTIFY: - /* - * - * Verify the channel - * - */ - pciu = MPTOPCIU(curp); - if(pciu){ - reply->m_cid = (unsigned long) pciu->cid; - } - else{ - reply->m_cid = ~0L; - } - break; - - case CA_PROTO_SEARCH: - reply->m_cid = curp->m_cid; - break; - - case CA_PROTO_EVENTS_ON: - case CA_PROTO_EVENTS_OFF: - case CA_PROTO_READ_SYNC: - case CA_PROTO_SNAPSHOT: - default: - reply->m_cid = ~0L; - break; + ar = 0; /* none */ + if(asCheckGet(pciu->asClientPVT)){ + ar |= CA_PROTO_ACCESS_RIGHT_READ; + } + if(asCheckPut(pciu->asClientPVT)){ + ar |= CA_PROTO_ACCESS_RIGHT_WRITE; } - /* - * copy back the request protocol - * (in network byte order) - */ - reply[1].m_postsize = htons (curp->m_postsize); - reply[1].m_cmmd = htons (curp->m_cmmd); - reply[1].m_type = htons (curp->m_type); - reply[1].m_count = htons (curp->m_count); - reply[1].m_cid = curp->m_cid; - reply[1].m_available = curp->m_available; - - /* - * add their context string into the protocol - */ - pMsgString = (char *) (reply+2); - status = vsprintf(pMsgString, pformat, args); - - /* - * force string post size to be the true size rounded to even - * boundary - */ - size = strlen(pMsgString)+1; - size += sizeof(*curp); - reply->m_postsize = size; - END_MSG(client); - -} - - -/* - * logBadIdWithFileAndLineno() - */ -LOCAL void logBadIdWithFileAndLineno( -struct client *client, -caHdr *mp, -char *pFileName, -unsigned lineno -) -{ - log_header(mp,0); - SEND_LOCK(client); - send_err( - mp, - ECA_INTERNAL, - client, - "Bad Resource ID at %s.%d", - pFileName, - lineno); - SEND_UNLOCK(client); -} - - -/* log_header() - * - * Debug aid - print the header part of a message. - * - */ -LOCAL void log_header( -caHdr *mp, -int mnum -) -{ - struct channel_in_use *pciu; - - pciu = MPTOPCIU(mp); - - logMsg ( -"CAS header: cmmd=%d cid=0x%x type=%d count=%d postsize=%u available=0x%x\n", - mp->m_cmmd, - mp->m_cid, - mp->m_type, - mp->m_count, - (unsigned)mp->m_postsize, - (unsigned)mp->m_available); - - - logMsg( "CAS: \tN=%d paddr=%x\n", - mnum, - (int)(pciu?&pciu->addr:NULL), - NULL, - NULL, - NULL, - NULL); - - if(mp->m_cmmd==CA_PROTO_WRITE && mp->m_type==DBF_STRING) - logMsg("CAS: The string written: %s \n", - (int)(mp+1), - NULL, - NULL, - NULL, - NULL, - NULL); -} - - - -/* - * - * cac_send_heartbeat() - * - * lock must be applied while in this routine - */ -void cas_send_heartbeat( -struct client *pc -) -{ - FAST caHdr *reply; - - reply = (caHdr *) ALLOC_MSG(pc, 0); - if(!reply){ - taskSuspend(0); - } + SEND_LOCK(pclient); + reply = (caHdr *)ALLOC_MSG(pclient, 0); + assert(reply); *reply = nill_msg; - reply->m_cmmd = CA_PROTO_NOOP; - - END_MSG(pc); - - return; + reply->m_cmmd = CA_PROTO_ACCESS_RIGHTS; + reply->m_cid = pciu->cid; + reply->m_available = ar; + END_MSG(pclient); + SEND_UNLOCK(pclient); } - - -/* - * MPTOPCIU() - * - * used to be a macro - */ -LOCAL struct channel_in_use *MPTOPCIU (caHdr *mp) -{ - struct channel_in_use *pciu; - const unsigned id = mp->m_cid; - - FASTLOCK(&clientQlock); - pciu = bucketLookupItemUnsignedId (pCaBucket, &id); - FASTUNLOCK(&clientQlock); - - return pciu; -} - - /* * casAccessRightsCB() * @@ -2095,7 +1055,6 @@ LOCAL void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type) return; } - switch(type) { case asClientCOAR: @@ -2131,81 +1090,1150 @@ LOCAL void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type) } } - /* - * access_rights_reply() + * claim_ciu_action() */ -LOCAL void access_rights_reply(struct channel_in_use *pciu) +LOCAL int claim_ciu_action( +caHdr *mp, +struct client *client +) { - struct client *pclient; - caHdr *reply; - unsigned ar; - int v41; - - pclient = pciu->client; - - assert(pclient != prsrv_cast_client); + int v42; + int status; + struct channel_in_use *pciu; /* - * noop if this is an old client + * The available field is used (abused) + * here to communicate the miner version number + * starting with CA 4.1. The field was set to zero + * prior to 4.1 */ - v41 = CA_V41(CA_PROTOCOL_VERSION,pclient->minor_version_number); - if(!v41){ + client->minor_version_number = mp->m_available; + + if (CA_V44(CA_PROTOCOL_VERSION,client->minor_version_number)) { + struct dbAddr tmp_addr; + + status = db_name_to_addr( + (char *)(mp+1), + &tmp_addr); + if (status < 0) { + return OK; + } + + DLOG(2,"CAS: claim_ciu_action found '%s', type %d, count %d\n", + (int) (mp+1), + tmp_addr.dbr_field_type, + tmp_addr.no_elements, + NULL, NULL, NULL); + + pciu = casCreateChannel ( + client, + &tmp_addr, + mp->m_cid); + if (!pciu) { + SEND_LOCK(client); + send_err(mp, + ECA_ALLOCMEM, + client, + RECORD_NAME(&tmp_addr)); + SEND_UNLOCK(client); + return ERROR; + } + } + else { + FASTLOCK(&prsrv_cast_client->addrqLock); + /* + * clients which dont claim their + * channel in use block prior to + * timeout must reconnect + */ + pciu = MPTOPCIU(mp); + if(!pciu){ + logMsg("CAS: client timeout disconnect id=%d\n", + mp->m_cid, + NULL, + NULL, + NULL, + NULL, + NULL); + FASTUNLOCK(&prsrv_cast_client->addrqLock); + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "old connect protocol timed out"); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * duplicate claim message are unacceptable + * (so we disconnect the client) + */ + if (pciu->client!=prsrv_cast_client) { + logMsg("CAS: duplicate claim disconnect id=%d\n", + mp->m_cid, + NULL, + NULL, + NULL, + NULL, + NULL); + FASTUNLOCK(&prsrv_cast_client->addrqLock); + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "duplicate claim in old connect protocol"); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * 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( + &prsrv_cast_client->addrq, + &pciu->node); + FASTUNLOCK(&prsrv_cast_client->addrqLock); + + FASTLOCK(&prsrv_cast_client->addrqLock); + pciu->client = client; + ellAdd(&client->addrq, &pciu->node); + FASTUNLOCK(&prsrv_cast_client->addrqLock); + } + + + /* + * set up access security for this channel + */ + status = asAddClient( + &pciu->asClientPVT, + asDbGetMemberPvt(&pciu->addr), + asDbGetAsl(&pciu->addr), + client->pUserName, + client->pHostName); + if(status != 0 && status != S_asLib_asNotActive){ + SEND_LOCK(client); + send_err(mp, ECA_ALLOCMEM, client, "No room for security table"); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * store ptr to channel in use block + * in access security private + */ + asPutClientPvt(pciu->asClientPVT, pciu); + + v42 = CA_V42( + CA_PROTOCOL_VERSION, + client->minor_version_number); + + /* + * register for asynch updates of access rights changes + * (only after the lock is released, we are added to + * the correct client, and the clients version is + * known) + */ + status = asRegisterClientCallback( + pciu->asClientPVT, + casAccessRightsCB); + if(status == S_asLib_asNotActive){ + /* + * force the initial update + */ + access_rights_reply(pciu); + } + else if (status!=0) { + SEND_LOCK(client); + send_err(mp, ECA_ALLOCMEM, client, + "No room for access security state change subscription"); + SEND_UNLOCK(client); + return ERROR; + } + + if(v42){ + caHdr *claim_reply; + + SEND_LOCK(client); + claim_reply = (caHdr *) ALLOC_MSG(client, 0); + assert (claim_reply); + + *claim_reply = nill_msg; + claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU; + claim_reply->m_type = pciu->addr.dbr_field_type; + claim_reply->m_count = pciu->addr.no_elements; + claim_reply->m_cid = pciu->cid; + claim_reply->m_available = pciu->sid; + + DBLOCK(3, + printf ("claim_cui reply:\n"); + log_header (NULL, client, claim_reply, 0); + ) + + END_MSG(client); + SEND_UNLOCK(client); + } + return OK; +} + + +/* + * write_notify_call_back() + * + * (called by the db call back thread) + */ +LOCAL void write_notify_call_back(PUTNOTIFY *ppn) +{ + struct client *pclient; + struct channel_in_use *pciu; + + /* + * we choose to suspend the task if there + * is an internal failure + */ + pciu = (struct channel_in_use *) ppn->usrPvt; + assert(pciu); + assert(pciu->pPutNotify); + + if(!pciu->pPutNotify->busy){ + logMsg("Double DB put notify call back!!\n", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); return; } - ar = 0; /* none */ - if(asCheckGet(pciu->asClientPVT)){ - ar |= CA_PROTO_ACCESS_RIGHT_READ; - } - if(asCheckPut(pciu->asClientPVT)){ - ar |= CA_PROTO_ACCESS_RIGHT_WRITE; + pclient = pciu->client; + + /* + * independent lock used here in order to + * avoid any possibility of blocking + * the database (or indirectly blocking + * one client on another client). + */ + FASTLOCK(&pclient->putNotifyLock); + ellAdd(&pclient->putNotifyQue, &pciu->pPutNotify->node); + FASTUNLOCK(&pclient->putNotifyLock); + + /* + * offload the labor for this to the + * event task so that we never block + * the db or another client. + */ + db_post_extra_labor(pclient->evuser); +} + + +/* + * write_notify_reply() + * + * (called by the CA server event task via the extra labor interface) + */ +void write_notify_reply(void *pArg) +{ + RSRVPUTNOTIFY *ppnb; + struct client *pClient; + caHdr *preply; + int status; + + pClient = pArg; + + SEND_LOCK(pClient); + while(TRUE){ + /* + * independent lock used here in order to + * avoid any possibility of blocking + * the database (or indirectly blocking + * one client on another client). + */ + FASTLOCK(&pClient->putNotifyLock); + ppnb = (RSRVPUTNOTIFY *)ellGet(&pClient->putNotifyQue); + FASTUNLOCK(&pClient->putNotifyLock); + /* + * break to loop exit + */ + if(!ppnb){ + break; + } + + /* + * aquire sufficient output buffer + */ + preply = ALLOC_MSG(pClient, 0); + if (!preply) { + /* + * inability to aquire buffer space + * Indicates corruption + */ + logMsg("CA server corrupted - put call back(s) discarded\n", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + break; + } + *preply = ppnb->msg; + /* + * + * Map from DB status to CA status + * + * the channel id field is being abused to carry + * status here + */ + if(ppnb->dbPutNotify.status){ + if(ppnb->dbPutNotify.status == S_db_Blocked){ + preply->m_cid = ECA_PUTCBINPROG; + } + else{ + preply->m_cid = ECA_PUTFAIL; + } + } + else{ + preply->m_cid = ECA_NORMAL; + } + + /* commit the message */ + END_MSG(pClient); + ppnb->busy = FALSE; } - SEND_LOCK(pclient); - reply = (caHdr *)ALLOC_MSG(pclient, 0); - assert(reply); + cas_send_msg(pClient,FALSE); - *reply = nill_msg; - reply->m_cmmd = CA_PROTO_ACCESS_RIGHTS; - reply->m_cid = pciu->cid; - reply->m_available = ar; - END_MSG(pclient); - SEND_UNLOCK(pclient); + SEND_UNLOCK(pClient); + + /* + * wakeup the TCP thread if it is waiting for a cb to complete + */ + status = semGive(pClient->blockSem); + if(status != OK){ + logMsg("CA block sem corrupted\n", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + } +} + +/* + * putNotifyErrorReply + */ +LOCAL void putNotifyErrorReply(struct client *client, caHdr *mp, int statusCA) +{ + caHdr *preply; + + SEND_LOCK(client); + preply = ALLOC_MSG(client, 0); + if(!preply){ + logMsg("Fatal Error:%s, %d\n", + (int)__FILE__, + __LINE__, + NULL, + NULL, + NULL, + NULL); + taskSuspend(0); + } + + *preply = *mp; + /* + * the cid field abused to contain status + * during put cb replies + */ + preply->m_cid = statusCA; + END_MSG(client); + SEND_UNLOCK(client); +} + +/* + * write_notify_action() + */ +LOCAL int write_notify_action( +caHdr *mp, +struct client *client +) +{ + unsigned long size; + int status; + struct channel_in_use *pciu; + + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return ERROR; + } + + if (mp->m_type > LAST_BUFFER_TYPE) { + putNotifyErrorReply(client, mp, ECA_BADTYPE); + return ERROR; + } + + if(!asCheckPut(pciu->asClientPVT)){ + putNotifyErrorReply(client, mp, ECA_NOWTACCESS); + return OK; + } + + size = dbr_size_n(mp->m_type, mp->m_count); + + if(pciu->pPutNotify){ + /* + * serialize concurrent put notifies + */ + while(pciu->pPutNotify->busy){ + status = semTake( + client->blockSem, + sysClkRateGet()*60); + if(status != OK && pciu->pPutNotify->busy){ + log_header("put call back time out", client, mp,0); + dbNotifyCancel(&pciu->pPutNotify->dbPutNotify); + pciu->pPutNotify->busy = FALSE; + putNotifyErrorReply( + client, + mp, + ECA_PUTCBINPROG); + return OK; + } + } + + /* + * if not busy then free the current + * block if it is to small + */ + if(pciu->pPutNotify->valueSizepPutNotify); + pciu->pPutNotify = NULL; + } + } + + /* + * send error and go to next request + * if there isnt enough memory left + */ + if(!pciu->pPutNotify){ + pciu->pPutNotify = (RSRVPUTNOTIFY *) + casCalloc(1, sizeof(*pciu->pPutNotify)+size); + if(!pciu->pPutNotify){ + putNotifyErrorReply(client, mp, ECA_ALLOCMEM); + return ERROR; + } + pciu->pPutNotify->valueSize = size; + pciu->pPutNotify->dbPutNotify.pbuffer = (pciu->pPutNotify+1); + pciu->pPutNotify->dbPutNotify.usrPvt = pciu; + pciu->pPutNotify->dbPutNotify.paddr = &pciu->addr; + pciu->pPutNotify->dbPutNotify.userCallback = write_notify_call_back; + } + + pciu->pPutNotify->busy = TRUE; + pciu->pPutNotify->msg = *mp; + pciu->pPutNotify->dbPutNotify.nRequest = mp->m_count; +#ifdef CONVERSION_REQUIRED + /* use type as index into conversion jumptable */ + (* cac_dbr_cvrt[mp->m_type]) + ( mp + 1, + pciu->pPutNotify->dbPutNotify.pbuffer, + FALSE, /* net -> host format */ + mp->m_count); +#else + memcpy(pciu->pPutNotify->dbPutNotify.pbuffer, (char *)(mp+1), size); +#endif + status = dbPutNotifyMapType(&pciu->pPutNotify->dbPutNotify, mp->m_type); + if(status){ + putNotifyErrorReply(client, mp, ECA_PUTFAIL); + pciu->pPutNotify->busy = FALSE; + return OK; + } + + status = dbPutNotify(&pciu->pPutNotify->dbPutNotify); + if(status && status != S_db_Pending){ + /* + * let the call back take care of failure + * even if it is immediate + */ + pciu->pPutNotify->dbPutNotify.status = status; + (*pciu->pPutNotify->dbPutNotify.userCallback) + (&pciu->pPutNotify->dbPutNotify); + } + return OK; +} + +/* + * + * event_add_action() + * + */ +LOCAL int event_add_action( +caHdr *mp, +struct client *client +) +{ + struct monops *pmo = (struct monops *) mp; + struct channel_in_use *pciu; + struct event_ext *pevext; + int status; + int size; + + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return ERROR; + } + + pevext = (struct event_ext *) freeListMalloc(rsrvEventFreeList); + size = db_sizeof_event_block() + sizeof(*pevext); + if (!pevext) { + SEND_LOCK(client); + send_err( + mp, + ECA_ALLOCMEM, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return ERROR; + } + +#ifdef CONVERSION_REQUIRED + + /* I convert here is the full message that we get, + * though only m_mask seems to be used + */ + dbr_ntohf (&pmo->m_info.m_lval , &pmo->m_info.m_lval); + dbr_ntohf (&pmo->m_info.m_hval , &pmo->m_info.m_hval); + dbr_ntohf (&pmo->m_info.m_toval, &pmo->m_info.m_toval); + pmo->m_info.m_mask = ntohs (pmo->m_info.m_mask); +#endif + + memset(pevext,0,size); + pevext->msg = *mp; + pevext->pciu = pciu; + pevext->send_lock = TRUE; + pevext->size = dbr_size_n(mp->m_type, mp->m_count); + pevext->mask = pmo->m_info.m_mask; + + FASTLOCK(&client->eventqLock); + ellAdd( &pciu->eventq, &pevext->node); + FASTUNLOCK(&client->eventqLock); + + pevext->pdbev = (struct event_block *)(pevext+1); + + status = db_add_event( + client->evuser, + &pciu->addr, + read_reply, + pevext, + pevext->mask, + pevext->pdbev); + if (status == ERROR) { + pevext->pdbev = NULL; + SEND_LOCK(client); + send_err( + mp, + ECA_ADDFAIL, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * always send it once at event add + */ + /* + * if the client program issues many monitors + * in a row then I recv when the send side + * of the socket would block. This prevents + * a application program initiated deadlock. + * + * However when I am reconnecting I reissue + * the monitors and I could get deadlocked. + * The client is blocked sending and the server + * task for the client is blocked sending in + * this case. I cant check the recv part of the + * socket in the client since I am still handling an + * outstanding recv ( they must be processed in order). + * I handle this problem in the server by using + * post_single_event() below instead of calling + * read_reply() in this module. This is a complete + * fix since a monitor setup is the only request + * soliciting a reply in the client which is + * issued from inside of service.c (from inside + * of the part of the ca client which services + * messages sent by the server). + */ + + DLOG(3, "event_add_action: db_post_single_event (0x%X)\n", + (int) pevext->pdbev, 0, 0, 0, 0, 0); + db_post_single_event(pevext->pdbev); + + /* + * disable future labor if no read access + */ + if(!asCheckGet(pciu->asClientPVT)){ + db_event_disable(pevext->pdbev); + DLOG(3, "Disable event because cannot read\n", + 0, 0, 0, 0, 0, 0); + } + + return OK; } /* - * casCalloc() - * - * (dont drop below some max block threshold) + * clear_channel_reply() */ -LOCAL void *casCalloc(size_t count, size_t size) -{ - if (casBelowMaxBlockThresh) { - return NULL; - } - return calloc(count, size); + LOCAL int clear_channel_reply( + caHdr *mp, + struct client *client + ) + { + caHdr *reply; + struct event_ext *pevext; + struct channel_in_use *pciu; + int status; + + /* + * + * Verify the channel + * + */ + pciu = MPTOPCIU(mp); + if(pciu?pciu->client!=client:TRUE){ + logBadId(client, mp); + return ERROR; + } + + /* + * if a put notify is outstanding then cancel it + */ + if(pciu->pPutNotify){ + if(pciu->pPutNotify->busy){ + dbNotifyCancel(&pciu->pPutNotify->dbPutNotify); + } + } + + while (TRUE){ + FASTLOCK(&client->eventqLock); + pevext = (struct event_ext *) ellGet(&pciu->eventq); + FASTUNLOCK(&client->eventqLock); + + if(!pevext){ + break; + } + + if(pevext->pdbev){ + status = db_cancel_event(pevext->pdbev); + assert(status == OK); + } + freeListFree(rsrvEventFreeList, pevext); + } + + status = db_flush_extra_labor_event(client->evuser); + if (status) { + SEND_LOCK(client); + send_err(mp, ECA_INTERNAL, client, + "extra labor event didnt flush"); + SEND_UNLOCK(client); + return ERROR; + } + + if (pciu->pPutNotify) { + free (pciu->pPutNotify); + } + + /* + * send delete confirmed message + */ + SEND_LOCK(client); + reply = (caHdr *) ALLOC_MSG(client, 0); + if (!reply) { + SEND_UNLOCK(client); + return ERROR; + } + *reply = *mp; + + END_MSG(client); + SEND_UNLOCK(client); + + FASTLOCK(&client->addrqLock); + ellDelete(&client->addrq, &pciu->node); + FASTUNLOCK(&client->addrqLock); + + /* + * remove from access control list + */ + status = asRemoveClient(&pciu->asClientPVT); + assert(status == 0 || status == S_asLib_asNotActive); + if(status != 0 && status != S_asLib_asNotActive){ + errMessage(status, RECORD_NAME(&pciu->addr)); + } + + FASTLOCK(&clientQlock); + status = bucketRemoveItemUnsignedId (pCaBucket, &pciu->sid); + if(status != S_bucket_success){ + errMessage (status, "Bad resource id during channel clear"); + logBadId(client, mp); + } + FASTUNLOCK(&clientQlock); + freeListFree(rsrvChanFreeList, pciu); + + return OK; } + /* - * casMalloc() * - * (dont drop below some max block threshold) + * event_cancel_reply() + * + * + * Much more efficient now since the event blocks hang off the channel in use + * blocks not all together off the client block. */ -LOCAL void *casMalloc(size_t size) +LOCAL int event_cancel_reply( + caHdr *mp, + struct client *client + ) { - if (casBelowMaxBlockThresh) { - return NULL; - } - return malloc(size); + struct channel_in_use *pciu; + caHdr *reply; + struct event_ext *pevext; + int status; + + /* + * + * Verify the channel + * + */ + pciu = MPTOPCIU(mp); + if (pciu?pciu->client!=client:TRUE) { + logBadId(client, mp); + return ERROR; + } + + /* + * search events on this channel for a match + * (there are usually very few monitors per channel) + */ + FASTLOCK(&client->eventqLock); + for (pevext = (struct event_ext *) ellFirst(&pciu->eventq); + pevext; pevext = (struct event_ext *) ellNext(&pevext->node)){ + + if (pevext->msg.m_available == mp->m_available) { + ellDelete(&pciu->eventq, &pevext->node); + break; + } + } + FASTUNLOCK(&client->eventqLock); + + /* + * Not Found- return an exception event + */ + if(!pevext){ + SEND_LOCK(client); + send_err(mp, ECA_BADMONID, client, RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return ERROR; + } + + /* + * cancel monitor activity in progress + */ + if(pevext->pdbev){ + status = db_cancel_event(pevext->pdbev); + if (status != OK) { + SEND_LOCK(client); + send_err(mp, ECA_INTERNAL, client, + "unable to remove monitor event subscription"); + SEND_UNLOCK(client); + return ERROR; + } + } + + /* + * send delete confirmed message + */ + SEND_LOCK(client); + reply = (caHdr *) ALLOC_MSG(client, 0); + if (!reply) { + SEND_UNLOCK(client); + return ERROR; + } + *reply = pevext->msg; + reply->m_postsize = 0; + + END_MSG(client); + SEND_UNLOCK(client); + + freeListFree (rsrvEventFreeList, pevext); + + return OK; } /* - * getNextRsrvResourceID() + * read_sync_reply() */ -unsigned getNextRsrvResourceID() +LOCAL int read_sync_reply( +caHdr *mp, +struct client *client +) { - return nextRsrvResourceID; + FAST caHdr *reply; + + SEND_LOCK(client); + reply = (caHdr *) ALLOC_MSG(client, 0); + if (!reply) { + SEND_UNLOCK(client); + return ERROR; + } + + *reply = *mp; + + END_MSG(client); + + SEND_UNLOCK(client); + + return OK; +} + +/* + * search_fail_reply() + * + * Only when requested by the client + * send search failed reply + */ +LOCAL void search_fail_reply( +caHdr *mp, +struct client *client +) +{ + FAST caHdr *reply; + + SEND_LOCK(client); + reply = (caHdr *) ALLOC_MSG(client, 0); + if (!reply) { + taskSuspend(0); + } + *reply = *mp; + reply->m_cmmd = CA_PROTO_NOT_FOUND; + reply->m_postsize = 0; + + END_MSG(client); + SEND_UNLOCK(client); + +} + +/* + * search_reply() + */ +LOCAL int search_reply( + caHdr *mp, + struct client *client + ) +{ + struct dbAddr tmp_addr; + caHdr *search_reply; + unsigned short *pMinorVersion; + int status; + unsigned sid; + unsigned long count; + ca_uint16_t type; + int spaceAvailOnFreeList; + + /* Exit quickly if channel not on this node */ + status = db_name_to_addr((char *) (mp+1), &tmp_addr); + if (status < 0) { + DLOG (2, "CAS: Lookup for channel \"%s\" failed\n", + (int)(mp+1), + NULL, + NULL, + NULL, + NULL, + NULL); + if (mp->m_type == DOREPLY) + search_fail_reply(mp, client); + return OK; + } + + /* + * stop further use of server if max block drops + * below MAX_BLOCK_THRESHOLD + */ + spaceAvailOnFreeList = freeListItemsAvail(rsrvClientFreeList)>0 + && freeListItemsAvail(rsrvChanFreeList)>0 + && freeListItemsAvail(rsrvEventFreeList)>0; + if (casBelowMaxBlockThresh && !spaceAvailOnFreeList) { + SEND_LOCK(client); + send_err(mp, + ECA_ALLOCMEM, + client, + "Server memory exhausted"); + SEND_UNLOCK(client); + return OK; + } + + /* + * starting with V4.4 the count field is used (abused) + * to store the minor version number of the client. + * + * New versions dont alloc the channel in response + * to a search request. + * + * m_count, m_cid are already in host format... + */ + if (CA_V44(CA_PROTOCOL_VERSION, mp->m_count)) { + sid = ~0U; + count = 0; + type = ca_server_port; + } + else { + struct channel_in_use *pchannel; + + pchannel = casCreateChannel ( + client, + &tmp_addr, + mp->m_cid); + if (!pchannel) { + SEND_LOCK(client); + send_err(mp, + ECA_ALLOCMEM, + client, + RECORD_NAME(&tmp_addr)); + SEND_UNLOCK(client); + return OK; + } + sid = pchannel->sid; + count = tmp_addr.no_elements; + type = (ca_uint16_t) tmp_addr.dbr_field_type; + } + + SEND_LOCK(client); + + search_reply = (caHdr *) + ALLOC_MSG(client, sizeof(*pMinorVersion)); + if (!search_reply) { + SEND_UNLOCK(client); + return ERROR; + } + + *search_reply = *mp; + search_reply->m_postsize = sizeof(*pMinorVersion); + + /* this field for rmt machines where paddr invalid */ + search_reply->m_type = type; + search_reply->m_count = count; + search_reply->m_cid = sid; + + /* + * Starting with CA V4.1 the minor version number + * is appended to the end of each search reply. + * This value is ignored by earlier clients. + */ + pMinorVersion = (unsigned short *)(search_reply+1); + *pMinorVersion = htons(CA_MINOR_VERSION); + + END_MSG(client); + SEND_UNLOCK(client); + + return OK; +} + +/* + * + * cac_send_heartbeat() + * + * lock must be applied while in this routine + */ +void cas_send_heartbeat( +struct client *pc +) +{ + FAST caHdr *reply; + + reply = (caHdr *) ALLOC_MSG(pc, 0); + if(!reply){ + taskSuspend(0); + } + + *reply = nill_msg; + reply->m_cmmd = CA_PROTO_NOOP; + + END_MSG(pc); + + return; +} + +typedef int (*pProtoStub) (caHdr *mp, struct client *client); + +/* + * TCP protocol jump table + */ +LOCAL const pProtoStub tcpJumpTable[] = +{ + noop_action, + event_add_action, + event_cancel_reply, + read_action, + write_action, + bad_tcp_cmd_action, + bad_tcp_cmd_action, + bad_tcp_cmd_action, + events_off_action, + events_on_action, + read_sync_reply, + bad_tcp_cmd_action, + clear_channel_reply, + bad_tcp_cmd_action, + bad_tcp_cmd_action, + read_action, + bad_tcp_cmd_action, + bad_tcp_cmd_action, + claim_ciu_action, + write_notify_action, + client_name_action, + host_name_action, + bad_tcp_cmd_action, + echo_action, + bad_tcp_cmd_action, + bad_tcp_cmd_action, + bad_tcp_cmd_action, + bad_tcp_cmd_action +}; + +/* + * UDP protocol jump table + */ +LOCAL const pProtoStub udpJumpTable[] = +{ + noop_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + search_reply, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + echo_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action, + bad_udp_cmd_action +}; + + +/* + * CAMESSAGE() + */ +int camessage( + struct client *client, + struct message_buffer *recv + ) +{ + unsigned long tmp_postsize; + int nmsg = 0; + unsigned long msgsize; + unsigned long bytes_left; + int status; + caHdr *mp; + + if(!pCaBucket){ + pCaBucket = bucketCreate(CAS_HASH_TABLE_SIZE); + if(!pCaBucket){ + return ERROR; + } + } + + DLOG (2, "CAS: Parsing %d(decimal) bytes\n", + recv->cnt, NULL, NULL, NULL, NULL, NULL); + + bytes_left = recv->cnt; + while (bytes_left) + { + + /* assert that we have at least a complete caHdr */ + if(bytes_left < sizeof(*mp)) + return OK; + + mp = (caHdr *) &recv->buf[recv->stk]; + + /* problem: we have a complete header, + * but before we check msgsize we don't know + * if we have a complete message body + * -> we may be called again with the same header + * after receiving the full message + */ + tmp_postsize = ntohs (mp->m_postsize); + msgsize = tmp_postsize + sizeof(*mp); + + if (msgsize > bytes_left) + return OK; + + /* Have complete message (header + content) + * -> convert the header elements + */ + mp->m_cmmd = ntohs (mp->m_cmmd); + mp->m_postsize = tmp_postsize; + mp->m_type = ntohs (mp->m_type); + mp->m_count = ntohs (mp->m_count); + mp->m_cid = ntohl (mp->m_cid); + mp->m_available = ntohl (mp->m_available); + + nmsg++; + + if (CASDEBUG > 2) + log_header(NULL, client, mp, nmsg); + + if (client==prsrv_cast_client) { + if (mp->m_cmmdm_cmmd])(mp, client); + if (status!=OK) { + return ERROR; + } + } + else { + return bad_udp_cmd_action (mp, client); + } + } + else { + if (mp->m_cmmdm_cmmd])(mp, client); + if (status!=OK) { + return ERROR; + } + } + else { + return bad_tcp_cmd_action (mp, client); + } + } + + recv->stk += msgsize; + bytes_left = recv->cnt - recv->stk; + } + + return OK; } \ No newline at end of file diff --git a/src/rsrv/camsgtask.c b/src/rsrv/camsgtask.c index c21b262d8..56c476717 100644 --- a/src/rsrv/camsgtask.c +++ b/src/rsrv/camsgtask.c @@ -213,16 +213,9 @@ FAST int sock; if(CASDEBUG>0){ char buf[64]; - logMsg( "CAS: Recieved connection request\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - ipAddrToA (&client->addr, buf, sizeof(buf)); - logMsg( "from addr %s\n", - (int) /* sic */ buf, + ipAddrToA (&client->addr, buf, sizeof(buf)); + logMsg( "CAS: conn req from %s\n", + (int) /* sic */ buf, NULL, NULL, NULL, @@ -356,11 +349,18 @@ FAST int sock; client->recv.cnt = 0ul; } }else{ + char buf[64]; + client->recv.cnt = 0ul; + /* - * disconnect on message alignment - * problems + * disconnect when there are severe message errors */ + ipAddrToA (&client->addr, buf, sizeof(buf)); + logMsg ("CAS: forcing disconnect from %s\n", + /* sic */ (int) buf, NULL, NULL, + NULL, NULL, NULL); + break; } diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c index b269c46ee..947bb183a 100644 --- a/src/rsrv/caserverio.c +++ b/src/rsrv/caserverio.c @@ -70,7 +70,7 @@ int lock_needed; { int status; - if(CASDEBUG>2){ + if(CASDEBUG>2 && pclient->send.stk){ logMsg( "CAS: Sending a message of %d bytes\n", pclient->send.stk, NULL, diff --git a/src/rsrv/caservertask.c b/src/rsrv/caservertask.c index ee958d506..7f5dc0a65 100644 --- a/src/rsrv/caservertask.c +++ b/src/rsrv/caservertask.c @@ -67,6 +67,9 @@ static char *sccsId = "@(#) $Id$"; #include "task_params.h" #include "envDefs.h" #include "freeList.h" +#include "errlog.h" +#include "bsdSocketResource.h" + #include "server.h" LOCAL int terminate_one_client(struct client *client); @@ -477,8 +480,6 @@ void casr (unsigned level) freeListItemsAvail (rsrvChanFreeList), freeListItemsAvail (rsrvEventFreeList)); - printf ("The next resource ID allocated will be %u\n", getNextRsrvResourceID()); - if(pCaBucket){ printf( "The server's resource id conversion table:\n"); FASTLOCK(&clientQlock); @@ -500,12 +501,14 @@ LOCAL void log_one_client(struct client *client, unsigned level) { int i; struct channel_in_use *pciu; - struct sockaddr_in *psaddr; char *pproto; float send_delay; float recv_delay; unsigned long bytes_reserved; char *state[] = {"up", "down"}; + char clientHostName[128]; + + ipAddrToA (&client->addr, clientHostName, sizeof(clientHostName)); if(client->proto == IPPROTO_UDP){ pproto = "UDP"; @@ -521,9 +524,10 @@ LOCAL void log_one_client(struct client *client, unsigned level) recv_delay = delay_in_ticks(client->ticks_at_last_recv); printf( -"Client Name=\"%s\", Client Host=\"%s\", V%d.%u, Channel Count=%d\n", - client->pUserName, + "%s(%s): User=\"%s\", V%d.%u, Channel Count=%d\n", + clientHostName, client->pHostName, + client->pUserName, CA_PROTOCOL_VERSION, client->minor_version_number, ellCount(&client->addrq)); @@ -537,18 +541,10 @@ LOCAL void log_one_client(struct client *client, unsigned level) send_delay/sysClkRateGet(), recv_delay/sysClkRateGet()); printf( - "\tUnprocessed request bytes=%lu, Undelivered response bytes=%lu\n", + "\tUnprocessed request bytes=%lu, Undelivered response bytes=%lu, State=%s\n", client->send.stk, - client->recv.cnt - client->recv.stk); - psaddr = &client->addr; - printf( - "\tRemote Address %lu.%lu.%lu.%lu Remote Port %d State=%s\n", - (psaddr->sin_addr.s_addr & 0xff000000) >> 24, - (psaddr->sin_addr.s_addr & 0x00ff0000) >> 16, - (psaddr->sin_addr.s_addr & 0x0000ff00) >> 8, - (psaddr->sin_addr.s_addr & 0x000000ff), - psaddr->sin_port, - state[client->disconnect?1:0]); + client->recv.cnt - client->recv.stk, + state[client->disconnect?1:0]); } if (level>=2u) { diff --git a/src/rsrv/cast_server.c b/src/rsrv/cast_server.c index b5ee0e3e0..f390104b9 100644 --- a/src/rsrv/cast_server.c +++ b/src/rsrv/cast_server.c @@ -102,8 +102,8 @@ int cast_server(void) int count=0; struct sockaddr_in new_recv_addr; int recv_addr_size; - unsigned nchars; unsigned short port; + int nchars; taskwdInsert((int)taskIdCurrent,NULL,NULL); @@ -111,30 +111,19 @@ int cast_server(void) recv_addr_size = sizeof(new_recv_addr); - if( IOC_cast_sock!=0 && IOC_cast_sock!=ERROR ) - if( (status = close(IOC_cast_sock)) == ERROR ) - logMsg("CAS: Unable to close master cast socket\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + if( IOC_cast_sock!=0 && IOC_cast_sock!=ERROR ) { + if( (status = close(IOC_cast_sock)) == ERROR ) { + epicsPrintf ("CAS: Unable to close master cast socket\n"); + } + } /* * Open the socket. * Use ARPA Internet address format and datagram socket. - * Format described in . - */ + */ if((IOC_cast_sock = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR){ - logMsg("CAS: casts socket creation error\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + epicsPrintf ("CAS: casts socket creation error\n"); taskSuspend(taskIdSelf()); } @@ -158,182 +147,153 @@ int cast_server(void) status = setsockopt (IOC_cast_sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); if (status<0) { - logMsg("CAS: unable to set cast socket size\n", - NULL, NULL, NULL, NULL, NULL, NULL); + epicsPrintf ("CAS: unable to set cast socket size\n"); } } #endif + + /* Zero the sock_addr structure */ + bfill((char *)&sin, sizeof(sin), 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); + + /* get server's Internet address */ + if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) == ERROR){ + epicsPrintf ("CAS: cast bind error\n"); + close (IOC_cast_sock); + taskSuspend(0); + } + + /* tell clients we are on line again */ + status = taskSpawn( + CA_ONLINE_NAME, + CA_ONLINE_PRI, + CA_ONLINE_OPT, + CA_ONLINE_STACK, + rsrv_online_notify_task, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if(status==ERROR){ + epicsPrintf ("CAS: couldnt start up online notify task because \"%s\"\n", + strerror(errnoGet())); + } + + + /* + * setup new client structure but reuse old structure if + * possible + * + */ + while(TRUE){ + prsrv_cast_client = create_udp_client(IOC_cast_sock); + if(prsrv_cast_client){ + break; + } + taskDelay(sysClkRateGet()*60*5); + } + + while (TRUE) { + status = recvfrom ( + IOC_cast_sock, + prsrv_cast_client->recv.buf, + sizeof(prsrv_cast_client->recv.buf), + NULL, + (struct sockaddr *)&new_recv_addr, + &recv_addr_size); + if (status<0) { + epicsPrintf ("CAS: UDP recv error (errno=%d)\n", + errnoGet()); + taskDelay (sysClkRateGet()); + } + else { + prsrv_cast_client->recv.cnt = (unsigned long) status; + prsrv_cast_client->recv.stk = 0ul; + prsrv_cast_client->ticks_at_last_recv = tickGet(); - /* Zero the sock_addr structure */ - bfill((char *)&sin, sizeof(sin), 0); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(port); - - /* get server's Internet address */ - if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) == ERROR){ - logMsg("CAS: cast bind error\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - close (IOC_cast_sock); - taskSuspend(0); - } + /* + * If we are talking to a new client flush to the old one + * in case we are holding UDP messages waiting to + * see if the next message is for this same client. + */ + if (prsrv_cast_client->send.stk) { + status = bcmp( + (char *)&prsrv_cast_client->addr, + (char *)&new_recv_addr, + recv_addr_size); + if(status){ + /* + * if the address is different + */ + cas_send_msg(prsrv_cast_client, TRUE); + prsrv_cast_client->addr = new_recv_addr; + } + } + else { + prsrv_cast_client->addr = new_recv_addr; + } - /* tell clients we are on line again */ - status = taskSpawn( - CA_ONLINE_NAME, - CA_ONLINE_PRI, - CA_ONLINE_OPT, - CA_ONLINE_STACK, - rsrv_online_notify_task, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); - if(status==ERROR){ - logMsg("CAS: couldnt start up online notify task because \"%s\"\n", - (int) /* sic */ strerror(errnoGet()), - NULL, - NULL, - NULL, - NULL, - NULL); - } + if(CASDEBUG>1){ + char buf[40]; + + ipAddrToA (&prsrv_cast_client->addr, buf, sizeof(buf)); + epicsPrintf ("CAS: cast server msg of %d bytes from addr %s\n", + prsrv_cast_client->recv.cnt, buf); + } + if(CASDEBUG>2) + count = ellCount(&prsrv_cast_client->addrq); - /* - * setup new client structure but reuse old structure if - * possible - * - */ - while(TRUE){ - prsrv_cast_client = create_udp_client(IOC_cast_sock); - if(prsrv_cast_client){ - break; - } - taskDelay(sysClkRateGet()*60*5); - } + status = camessage( + prsrv_cast_client,&prsrv_cast_client->recv); + if(status == OK){ + if(prsrv_cast_client->recv.cnt != + prsrv_cast_client->recv.stk){ + char buf[40]; + + ipAddrToA (&prsrv_cast_client->addr, buf, sizeof(buf)); + epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n", + prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf); + } + } + else { + char buf[40]; + + ipAddrToA (&prsrv_cast_client->addr, buf, sizeof(buf)); - while(TRUE){ + epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf); + } - status = recvfrom( - IOC_cast_sock, - prsrv_cast_client->recv.buf, - sizeof(prsrv_cast_client->recv.buf), - NULL, - (struct sockaddr *)&new_recv_addr, - &recv_addr_size); - if(status<0){ - logMsg("CAS: UDP recv error (errno=%d)\n", - errnoGet(), - NULL, - NULL, - NULL, - NULL, - NULL); - taskDelay(sysClkRateGet()); - continue; - } - - prsrv_cast_client->recv.cnt = (unsigned long) status; - prsrv_cast_client->recv.stk = 0ul; - prsrv_cast_client->ticks_at_last_recv = tickGet(); + if(CASDEBUG>2){ + if(ellCount(&prsrv_cast_client->addrq)){ + epicsPrintf ("CAS: Fnd %d name matches (%d tot)\n", + ellCount(&prsrv_cast_client->addrq)-count, + ellCount(&prsrv_cast_client->addrq)); + } + } + } /* - * If we are talking to a new client flush the old one - * in case it is holding UDP messages waiting to - * see if the next message is for this same client. + * allow messages to batch up if more are comming */ - status = bcmp( - (char *)&prsrv_cast_client->addr, - (char *)&new_recv_addr, - recv_addr_size); - if(status){ - /* - * if the address is different - */ - cas_send_msg(prsrv_cast_client, TRUE); - prsrv_cast_client->addr = new_recv_addr; - } - - if(CASDEBUG>1){ - char buf[40]; - - logMsg( "CAS: cast server msg of %d bytes\n", - prsrv_cast_client->recv.cnt, - NULL, - NULL, - NULL, - NULL, - NULL); - ipAddrToA (&prsrv_cast_client->addr, buf, sizeof(buf)); - - logMsg( "CAS: from addr %s \n", - (int)buf, - NULL, - NULL, - NULL, - NULL, - NULL); - } - - if(CASDEBUG>2) - count = ellCount(&prsrv_cast_client->addrq); - - status = camessage( - prsrv_cast_client, - &prsrv_cast_client->recv); - if(status == OK){ - if(prsrv_cast_client->recv.cnt != - prsrv_cast_client->recv.stk){ - - logMsg( "CAS: partial UDP msg of %d bytes ?\n", - prsrv_cast_client->recv.cnt- - prsrv_cast_client->recv.stk, - NULL, - NULL, - NULL, - NULL, - NULL); - } - } - - if(CASDEBUG>2){ - if(ellCount(&prsrv_cast_client->addrq)){ - logMsg( "CAS: Fnd %d name matches (%d tot)\n", - ellCount(&prsrv_cast_client->addrq) - -count, - ellCount(&prsrv_cast_client->addrq), - NULL, - NULL, - NULL, - NULL); - } - } - - /* - * allow message to batch up if more are comming - */ - status = ioctl(IOC_cast_sock, FIONREAD, (int) &nchars); + status = ioctl(IOC_cast_sock, FIONREAD, /* sic */(int) &nchars); if(status == ERROR){ - taskSuspend(0); + taskSuspend(0); } - if(nchars == 0){ - cas_send_msg(prsrv_cast_client, TRUE); - clean_addrq(); - } + if(nchars == 0){ + cas_send_msg(prsrv_cast_client, TRUE); + clean_addrq(); + } } } @@ -392,13 +352,8 @@ LOCAL void clean_addrq() # ifdef DEBUG if(ndelete){ - logMsg( "CAS: %d CA channels have expired after %d sec\n", - ndelete, - maxdelay / sysClkRateGet(), - NULL, - NULL, - NULL, - NULL); + epicsPrintf ("CAS: %d CA channels have expired after %d sec\n", + ndelete, maxdelay / sysClkRateGet()); } # endif @@ -416,24 +371,12 @@ struct client *create_udp_client(unsigned sock) client = freeListMalloc(rsrvClientFreeList); if(!client){ - logMsg("CAS: no spae in pool for a new client\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + epicsPrintf ("CAS: no space in pool for a new client\n"); return NULL; } if(CASDEBUG>2) - logMsg( "CAS: Creating new udp client\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + epicsPrintf ("CAS: Creating new udp client\n"); /* * The following inits to zero done instead of a bfill since the send @@ -516,13 +459,7 @@ unsigned sock int addrSize; if(CASDEBUG>2){ - logMsg("CAS: converting udp client to tcp\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + epicsPrintf ("CAS: converting udp client to tcp\n"); } client->proto = IPPROTO_TCP; @@ -537,13 +474,7 @@ unsigned sock (struct sockaddr *)&client->addr, &addrSize); if(status == ERROR){ - logMsg("CAS: peer address fetch failed\n", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL); + epicsPrintf ("CAS: peer address fetch failed\n"); return ERROR; } diff --git a/src/rsrv/online_notify.c b/src/rsrv/online_notify.c index 6e840a12a..2312eadac 100644 --- a/src/rsrv/online_notify.c +++ b/src/rsrv/online_notify.c @@ -89,10 +89,10 @@ int rsrv_online_notify_task() &maxPeriod); if (longStatus || maxPeriod<=0.0) { maxPeriod = 15.0; - ca_printf ( + epicsPrintf ( "EPICS \"%s\" float fetch failed\n", EPICS_CA_BEACON_PERIOD.name); - ca_printf ( + epicsPrintf ( "Setting \"%s\" = %f\n", EPICS_CA_BEACON_PERIOD.name, maxPeriod);