From 0c7674036c71704ad8fd4c439063aa3f7ef66dd0 Mon Sep 17 00:00:00 2001 From: Jeff Hill Date: Thu, 10 Feb 2000 16:05:01 +0000 Subject: [PATCH] many changes --- src/rsrv/Makefile | 5 +- src/rsrv/camessage.c | 2522 +++++++++++++++++++------------------- src/rsrv/camsgtask.c | 372 ++---- src/rsrv/caserverio.c | 325 +++-- src/rsrv/caservertask.c | 980 +++++++++------ src/rsrv/cast_server.c | 474 +++---- src/rsrv/online_notify.c | 205 ++-- src/rsrv/server.h | 292 ++--- 8 files changed, 2463 insertions(+), 2712 deletions(-) diff --git a/src/rsrv/Makefile b/src/rsrv/Makefile index 697572ec1..be52c283b 100644 --- a/src/rsrv/Makefile +++ b/src/rsrv/Makefile @@ -7,8 +7,9 @@ USR_CFLAGS += -UUNIX -DiocCore rsrv_SRCS = \ caserverio.c caservertask.c camsgtask.c camessage.c \ - rsrv_init.c cast_server.c online_notify.c globalsource.c - + cast_server.c online_notify.c LIBRARY = rsrv +DLL_LIBS = Db As Com +SYS_DLL_LIBS := ws2_32 include $(TOP)/configure/RULES diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index e98881601..a7953a865 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -1,65 +1,37 @@ -/* - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 5-88 +/* + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 * - * Experimental Physics and Industrial Control System (EPICS) + * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * Modification Log: - * ----------------- - * .01 joh 012290 placed break in ca_cancel_event search so entire - * list is not searched. - * .02 joh 011091 added missing break to error message send - * chix select switch - * .03 joh 071291 now timestanmps channel in use block - * .04 joh 071291 code for CA_PROTO_CLAIM_CIU command - * .05 joh 082691 use db_post_single_event() instead of read_reply() - * to avoid deadlock condition between the client - * and the server. - * .06 joh 110491 lock added for CA_PROTO_CLAIM_CIU command - * .07 joh 021292 Better diagnostics - * .08 joh 021492 use lstFind() to verify chanel in clear_channel() - * .09 joh 031692 dont send exeception to the client if bad msg - * detected- just disconnect instead - * .10 joh 050692 added new routine - cas_send_heartbeat() - * .11 joh 062492 dont allow flow control to turn off gets - * .12 joh 090893 converted pointer to server id - * .13 joh 091493 made events on action a subroutine for debugging - * .14 joh 020194 New command added for CAV4.1 - client name - * .15 joh 052594 Removed CA_PROTO_BUILD cmd + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory */ - -static char *sccsId = "%W% %G%"; - #include #include #include #include #include -#include - #include "osiSock.h" #include "osiThread.h" #include "tsStamp.h" @@ -69,13 +41,12 @@ static char *sccsId = "%W% %G%"; #include "ellLib.h" #include "freeList.h" #include "caerr.h" -#include "osiSockResource.h" #include "server.h" static caHdr nill_msg; -#define RECORD_NAME(PADDR) ((PADDR)->precord->name) +#define RECORD_NAME(PADDR) ((PADDR)->precord->name) LOCAL EVENTFUNC read_reply; @@ -90,7 +61,7 @@ logBadIdWithFileAndLineno(CLIENT, MP, __FILE__, __LINE__) */ LOCAL void *casMalloc(size_t size) { - if (casBelowMaxBlockThresh) { + if (!casSufficentSpaceInPool) { return NULL; } return malloc(size); @@ -104,7 +75,7 @@ LOCAL void *casMalloc(size_t size) */ LOCAL void *casCalloc(size_t count, size_t size) { - if (casBelowMaxBlockThresh) { + if (!casSufficentSpaceInPool) { return NULL; } return calloc(count, size); @@ -117,21 +88,21 @@ LOCAL void *casCalloc(size_t count, size_t size) */ LOCAL struct channel_in_use *MPTOPCIU (const caHdr *mp) { - struct channel_in_use *pciu; - const unsigned id = mp->m_cid; + struct channel_in_use *pciu; + const unsigned id = mp->m_cid; - LOCK_CLIENTQ; - pciu = bucketLookupItemUnsignedId (pCaBucket, &id); - UNLOCK_CLIENTQ; + LOCK_CLIENTQ; + pciu = bucketLookupItemUnsignedId (pCaBucket, &id); + UNLOCK_CLIENTQ; - return pciu; + return pciu; } -/* send_err() +/* send_err() * - * reflect error msg back to the client + * reflect error msg back to the client * - * send buffer lock must be on while in this routine + * send buffer lock must be on while in this routine * */ LOCAL void send_err( @@ -139,118 +110,118 @@ const caHdr *curp, int status, struct client *client, const char *pformat, - ... + ... ) { - va_list args; + va_list args; struct channel_in_use *pciu; - int size; - caHdr *reply; - char *pMsgString; + int size; + caHdr *reply; + char *pMsgString; - va_start(args, pformat); + va_start(args, pformat); - /* - * allocate plenty of space for a sprintf() buffer - */ - reply = (caHdr *) ALLOC_MSG(client, 512); - if (!reply){ - int logMsgArgs[6]; - size_t i; + /* + * 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); - } + for(i=0; i< NELEMENTS(logMsgArgs); i++){ + logMsgArgs[i] = va_arg(args, int); + } - errlogPrintf( "caserver: Unable to deliver err msg to client => \"%s\"\n", - (int) ca_message(status)); - errlogPrintf( - (char *) pformat, - logMsgArgs[0], - logMsgArgs[1], - logMsgArgs[2], - logMsgArgs[3], - logMsgArgs[4], - logMsgArgs[5]); + errlogPrintf( "caserver: Unable to deliver err msg to client => \"%s\"\n", + (int) ca_message(status)); + errlogPrintf( + (char *) pformat, + logMsgArgs[0], + logMsgArgs[1], + logMsgArgs[2], + logMsgArgs[3], + logMsgArgs[4], + logMsgArgs[5]); - return; - } + return; + } - reply[0] = nill_msg; - reply[0].m_cmmd = CA_PROTO_ERROR; - reply[0].m_available = status; + 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; + 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_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; - } + 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_dataType = htons (curp->m_dataType); - reply[1].m_count = htons (curp->m_count); - reply[1].m_cid = curp->m_cid; - reply[1].m_available = curp->m_available; + /* + * 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_dataType = htons (curp->m_dataType); + 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); + /* + * 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); + /* + * 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() +/* log_header() * - * Debug aid - print the header part of a message. + * Debug aid - print the header part of a message. * */ LOCAL void log_header ( const char *pContext, struct client *client, const caHdr *mp, - int mnum + unsigned mnum ) { struct channel_in_use *pciu; @@ -258,27 +229,26 @@ LOCAL void log_header ( ipAddrToA (&client->addr, hostName, sizeof(hostName)); - pciu = MPTOPCIU(mp); + pciu = MPTOPCIU(mp); if (pContext) { - epicsPrintf ( -"CAS: request from %s => \"%s\"\n", + epicsPrintf ("CAS: request from %s => \"%s\"\n", hostName, pContext); } - epicsPrintf ( + 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_dataType, mp->m_count, mp->m_postsize); - epicsPrintf ( -"CAS: Request from %s => available=0x%x \tN=%d paddr=%x\n", + epicsPrintf ( +"CAS: Request from %s => available=0x%x \tN=%u paddr=%x\n", hostName, mp->m_available, mnum, (pciu?&pciu->addr:NULL)); if (mp->m_cmmd==CA_PROTO_WRITE && mp->m_dataType==DBF_STRING) { - epicsPrintf ( + epicsPrintf ( "CAS: Request from %s => \tThe string written: %s \n", - hostName, (mp+1)); + hostName, (mp+1)); } } @@ -286,118 +256,118 @@ LOCAL void log_header ( * logBadIdWithFileAndLineno() */ LOCAL void logBadIdWithFileAndLineno( -struct client *client, -caHdr *mp, -char *pFileName, -unsigned lineno +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); + 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); } /* * bad_tcp_cmd_action() */ LOCAL int bad_tcp_cmd_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { const char *pCtx = "invalid (damaged?) request code from TCP"; log_header (pCtx, client, mp, 0); /* - * by default, clients dont recover - * from this + * by default, clients dont recover + * from this */ SEND_LOCK (client); send_err (mp, ECA_INTERNAL, client, pCtx); SEND_UNLOCK (client); - return ERROR; + return RSRV_ERROR; } /* * bad_udp_cmd_action() */ LOCAL int bad_udp_cmd_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { log_header ("invalid (damaged?) request code from UDP", client, mp, 0); - return ERROR; + return RSRV_ERROR; } /* * noop_action() */ LOCAL int noop_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - return OK; + return RSRV_OK; } /* * echo_action() */ LOCAL int echo_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - caHdr *reply; + caHdr *reply; - SEND_LOCK(client); - reply = ALLOC_MSG(client, 0); + 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); + /* + * header (host) will we converted in send, + * content is still in net format: + */ + *reply = *mp; + END_MSG(client); } - SEND_UNLOCK(client); + SEND_UNLOCK(client); - return OK; + return RSRV_OK; } /* * events_on_action () */ LOCAL int events_on_action ( -caHdr *mp, +caHdr *mp, struct client *client ) { - db_event_flow_ctrl_mode_off(client->evuser); + db_event_flow_ctrl_mode_off(client->evuser); - return OK; + return RSRV_OK; } /* * events_off_action () */ LOCAL int events_off_action ( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - db_event_flow_ctrl_mode_on(client->evuser); + db_event_flow_ctrl_mode_on(client->evuser); - return OK; + return RSRV_OK; } /* @@ -409,413 +379,413 @@ struct client *client * compatibility */ LOCAL void no_read_access_event( -struct client *client, -struct event_ext *pevext +struct client *client, +struct event_ext *pevext ) { - caHdr *reply; - int v41; + caHdr *reply; + int v41; - v41 = CA_V41(CA_PROTOCOL_VERSION,client->minor_version_number); + v41 = CA_V41(CA_PROTOCOL_VERSION,client->minor_version_number); - /* - * continue to return an exception - * on failure to pre v41 clients - */ - if(!v41){ - send_err( - &pevext->msg, - ECA_GETFAIL, - client, - RECORD_NAME(&pevext->pciu->addr)); - return; - } + /* + * continue to return an exception + * on failure to pre v41 clients + */ + if(!v41){ + send_err( + &pevext->msg, + ECA_GETFAIL, + client, + RECORD_NAME(&pevext->pciu->addr)); + return; + } - 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; - memset((void *)(reply+1), 0, pevext->size); - END_MSG(client); - } + 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; + memset((void *)(reply+1), 0, pevext->size); + END_MSG(client); + } } /* - * read_reply() + * read_reply() */ LOCAL void read_reply( -void *pArg, -struct dbAddr *paddr, -int eventsRemaining, -db_field_log *pfl +void *pArg, +struct dbAddr *paddr, +int eventsRemaining, +db_field_log *pfl ) { - struct event_ext *pevext = pArg; - struct client *client = pevext->pciu->client; + struct event_ext *pevext = pArg; + struct client *client = pevext->pciu->client; struct channel_in_use *pciu = pevext->pciu; - caHdr *reply; - int status; - int strcnt; - int v41; + caHdr *reply; + int status; + int strcnt; + int v41; - if (pevext->send_lock) - SEND_LOCK(client); + if (pevext->send_lock) + SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, pevext->size); - if (!reply) { - send_err(&pevext->msg, ECA_TOLARGE, client, RECORD_NAME(paddr)); - if (!eventsRemaining) - cas_send_msg(client,!pevext->send_lock); - if (pevext->send_lock) - SEND_UNLOCK(client); - return; - } + reply = (caHdr *) ALLOC_MSG(client, pevext->size); + if (!reply) { + send_err(&pevext->msg, ECA_TOLARGE, client, RECORD_NAME(paddr)); + if (!eventsRemaining) + cas_send_msg(client,!pevext->send_lock); + if (pevext->send_lock) + SEND_UNLOCK(client); + return; + } - /* - * setup response message - */ - *reply = pevext->msg; - reply->m_postsize = pevext->size; - reply->m_cid = (unsigned long)pciu->cid; + /* + * setup response message + */ + *reply = pevext->msg; + reply->m_postsize = pevext->size; + reply->m_cid = (unsigned long)pciu->cid; - /* - * verify read access - */ - v41 = CA_V41(CA_PROTOCOL_VERSION,client->minor_version_number); - if(!asCheckGet(pciu->asClientPVT)){ - if(reply->m_cmmd==CA_PROTO_READ){ - if(v41){ - status = ECA_NORDACCESS; - } - else{ - status = ECA_GETFAIL; - } - /* - * old client & plain get & search/get - * continue to return an exception - * on failure - */ - send_err(&pevext->msg, status, - client, RECORD_NAME(paddr)); - } - else{ - no_read_access_event(client, pevext); - } - if (!eventsRemaining) - cas_send_msg(client,!pevext->send_lock); - if (pevext->send_lock){ - SEND_UNLOCK(client); - } - return; - } - status = db_get_field( - paddr, - pevext->msg.m_dataType, - reply + 1, - pevext->msg.m_count, - pfl); + /* + * verify read access + */ + v41 = CA_V41(CA_PROTOCOL_VERSION,client->minor_version_number); + if(!asCheckGet(pciu->asClientPVT)){ + if(reply->m_cmmd==CA_PROTO_READ){ + if(v41){ + status = ECA_NORDACCESS; + } + else{ + status = ECA_GETFAIL; + } + /* + * old client & plain get & search/get + * continue to return an exception + * on failure + */ + send_err(&pevext->msg, status, + client, RECORD_NAME(paddr)); + } + else{ + no_read_access_event(client, pevext); + } + if (!eventsRemaining) + cas_send_msg(client,!pevext->send_lock); + if (pevext->send_lock){ + SEND_UNLOCK(client); + } + return; + } + status = db_get_field( + paddr, + pevext->msg.m_dataType, + reply + 1, + pevext->msg.m_count, + pfl); - if (status < 0) { - /* - * I cant wait to redesign this protocol from scratch! - */ - if(!v41||reply->m_cmmd==CA_PROTO_READ){ - /* - * old client & plain get - * continue to return an exception - * on failure - */ - send_err(&pevext->msg, ECA_GETFAIL, client, RECORD_NAME(paddr)); - } - else{ - /* - * New clients recv the status of the - * operation directly to the - * event/put/get callback. - * - * Fetched value is set to zero in case they - * use it even when the status indicates - * failure. - * - * The m_cid field in the protocol - * header is abused to carry the status - */ - memset((void *)(reply+1), 0, pevext->size); - reply->m_cid = ECA_GETFAIL; - END_MSG(client); - } - } - else{ /* status of db_get_field >= 0 - * - * New clients recv the status of the - * operation directly to the - * event/put/get callback. - * - * The m_cid field in the protocol - * header is abused to carry the status - * - * get calls still use the - * m_cid field to identify the channel. - */ - if( v41 && reply->m_cmmd!=CA_PROTO_READ){ - reply->m_cid = ECA_NORMAL; - } - + if (status < 0) { + /* + * I cant wait to redesign this protocol from scratch! + */ + if(!v41||reply->m_cmmd==CA_PROTO_READ){ + /* + * old client & plain get + * continue to return an exception + * on failure + */ + send_err(&pevext->msg, ECA_GETFAIL, client, RECORD_NAME(paddr)); + } + else{ + /* + * New clients recv the status of the + * operation directly to the + * event/put/get callback. + * + * Fetched value is set to zero in case they + * use it even when the status indicates + * failure. + * + * The m_cid field in the protocol + * header is abused to carry the status + */ + memset((void *)(reply+1), 0, pevext->size); + reply->m_cid = ECA_GETFAIL; + END_MSG(client); + } + } + else{ /* status of db_get_field >= 0 + * + * New clients recv the status of the + * operation directly to the + * event/put/get callback. + * + * The m_cid field in the protocol + * header is abused to carry the status + * + * get calls still use the + * m_cid field to identify the channel. + */ + if( v41 && reply->m_cmmd!=CA_PROTO_READ){ + reply->m_cid = ECA_NORMAL; + } + #ifdef CONVERSION_REQUIRED - /* - * assert() is safe here because the type was - * checked by db_get_field() - */ - assert (pevext->msg.m_dataType < NELEMENTS(cac_dbr_cvrt)); + /* + * assert() is safe here because the type was + * checked by db_get_field() + */ + assert (pevext->msg.m_dataType < NELEMENTS(cac_dbr_cvrt)); - /* use type as index into conversion jumptable */ - (* cac_dbr_cvrt[pevext->msg.m_dataType]) - ( reply + 1, - reply + 1, - TRUE, /* host -> net format */ - pevext->msg.m_count); + /* use type as index into conversion jumptable */ + (* cac_dbr_cvrt[pevext->msg.m_dataType]) + ( reply + 1, + reply + 1, + TRUE, /* host -> net format */ + pevext->msg.m_count); #endif - /* - * force string message size to be the true size rounded to even - * boundary - */ - if (pevext->msg.m_dataType == DBR_STRING - && pevext->msg.m_count == 1) { - /* add 1 so that the string terminator will be shipped */ - strcnt = strlen((char *)(reply + 1)) + 1; - reply->m_postsize = strcnt; - } + /* + * force string message size to be the true size rounded to even + * boundary + */ + if (pevext->msg.m_dataType == DBR_STRING + && pevext->msg.m_count == 1) { + /* add 1 so that the string terminator will be shipped */ + strcnt = strlen((char *)(reply + 1)) + 1; + reply->m_postsize = strcnt; + } - END_MSG(client); - } + END_MSG(client); + } - /* - * Ensures timely response for events, but does que - * them up like db requests when the OPI does not keep up. - */ - if (!eventsRemaining) - cas_send_msg(client,!pevext->send_lock); + /* + * Ensures timely response for events, but does que + * them up like db requests when the OPI does not keep up. + */ + if (!eventsRemaining) + cas_send_msg(client,!pevext->send_lock); - if (pevext->send_lock) - SEND_UNLOCK(client); + if (pevext->send_lock) + SEND_UNLOCK(client); - return; + return; } /* * read_action() */ LOCAL int read_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - struct channel_in_use *pciu; - struct event_ext evext; + struct channel_in_use *pciu; + struct event_ext evext; - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - return ERROR; - } + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return RSRV_ERROR; + } - evext.msg = *mp; - evext.pciu = pciu; - evext.send_lock = TRUE; - evext.pdbev = NULL; - evext.size = dbr_size_n(mp->m_dataType, mp->m_count); + evext.msg = *mp; + evext.pciu = pciu; + evext.send_lock = TRUE; + evext.pdbev = NULL; + evext.size = dbr_size_n(mp->m_dataType, 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); + /* + * 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); - return OK; + return RSRV_OK; } /* * write_action() */ LOCAL int write_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - struct channel_in_use *pciu; + struct channel_in_use *pciu; int v41; long status; - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - return ERROR; - } + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return RSRV_ERROR; + } - if(!rsrvCheckPut(pciu)){ - 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); - return OK; - } - -#ifdef CONVERSION_REQUIRED - if (mp->m_dataType >= NELEMENTS(cac_dbr_cvrt)) { + if(!rsrvCheckPut(pciu)){ + 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, - ECA_PUTFAIL, - client, - RECORD_NAME(&pciu->addr)); - SEND_UNLOCK(client); - return ERROR; - } + send_err( + mp, + status, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return RSRV_OK; + } - /* use type as index into conversion jumptable */ - (* cac_dbr_cvrt[mp->m_dataType]) - ( mp + 1, - mp + 1, - FALSE, /* net -> host format */ - mp->m_count); +#ifdef CONVERSION_REQUIRED + if (mp->m_dataType >= NELEMENTS(cac_dbr_cvrt)) { + SEND_LOCK(client); + send_err( + mp, + ECA_PUTFAIL, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return RSRV_ERROR; + } + + /* use type as index into conversion jumptable */ + (* cac_dbr_cvrt[mp->m_dataType]) + ( mp + 1, + mp + 1, + FALSE, /* net -> host format */ + mp->m_count); #endif - status = db_put_field( - &pciu->addr, - mp->m_dataType, - 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; + status = db_put_field( + &pciu->addr, + mp->m_dataType, + 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 RSRV_OK; } /* * host_name_action() */ LOCAL int host_name_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - struct channel_in_use *pciu; - unsigned size; - char *pName; - char *pMalloc; - int status; + struct channel_in_use *pciu; + unsigned size; + char *pName; + char *pMalloc; + int status; - pName = (char *)(mp+1); - size = strlen(pName)+1; + 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; + send_err( + mp, + ECA_INTERNAL, + client, + "bad (very long) host name"); + SEND_UNLOCK(client); + return RSRV_ERROR; } - /* - * user name will not change if there isnt enough memory - */ - pMalloc = malloc(size); - if(!pMalloc){ + /* + * 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'; + send_err( + mp, + ECA_ALLOCMEM, + client, + "no room for new host name"); + SEND_UNLOCK(client); + return RSRV_ERROR; + } + strncpy( + pMalloc, + pName, + size-1); + pMalloc[size-1]='\0'; - semMutexMustTake(client->addrqLock); - pName = client->pHostName; - client->pHostName = pMalloc; - if(pName){ - free(pName); - } + semMutexMustTake(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){ - semMutexGive(client->addrqLock); + 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){ + semMutexGive(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; - } - semMutexGive(client->addrqLock); + send_err( + mp, + ECA_INTERNAL, + client, + "unable to install new host name into access security"); + SEND_UNLOCK(client); + return RSRV_ERROR; + } + pciu = (struct channel_in_use *) pciu->node.next; + } + semMutexGive(client->addrqLock); - DLOG(2, "CAS: host_name_action for \"%s\"\n", - (int) client->pHostName, - NULL, NULL, NULL, NULL, NULL); + DLOG(2, "CAS: host_name_action for \"%s\"\n", + (int) client->pHostName, + NULL, NULL, NULL, NULL, NULL); - return OK; + return RSRV_OK; } @@ -823,155 +793,155 @@ struct client *client * client_name_action() */ LOCAL int client_name_action( -caHdr *mp, -struct client *client +caHdr *mp, +struct client *client ) { - struct channel_in_use *pciu; - unsigned size; - char *pName; - char *pMalloc; - int status; + struct channel_in_use *pciu; + unsigned size; + char *pName; + char *pMalloc; + int status; - pName = (char *)(mp+1); - size = strlen(pName)+1; + 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; + send_err( + mp, + ECA_INTERNAL, + client, + "very long user name"); + SEND_UNLOCK(client); + return RSRV_ERROR; } - /* - * user name will not change if there isnt enough memory - */ - pMalloc = malloc(size); - if(!pMalloc){ + /* + * 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'; + send_err( + mp, + ECA_ALLOCMEM, + client, + "no memory for new user name"); + SEND_UNLOCK(client); + return RSRV_ERROR; + } + strncpy( + pMalloc, + pName, + size-1); + pMalloc[size-1]='\0'; - semMutexMustTake(client->addrqLock); - pName = client->pUserName; - client->pUserName = pMalloc; - if(pName){ - free(pName); - } + semMutexMustTake(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){ - semMutexGive(client->addrqLock); + 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){ + semMutexGive(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; - } - semMutexGive(client->addrqLock); + send_err( + mp, + ECA_INTERNAL, + client, + "unable to install new user name into access security"); + SEND_UNLOCK(client); + return RSRV_ERROR; + } + pciu = (struct channel_in_use *) pciu->node.next; + } + semMutexGive(client->addrqLock); - DLOG (2, "CAS: client_name_action for \"%s\"\n", - (int) client->pUserName, - NULL, NULL, NULL, NULL, NULL); + DLOG (2, "CAS: client_name_action for \"%s\"\n", + (int) client->pUserName, + NULL, NULL, NULL, NULL, NULL); - return OK; + return RSRV_OK; } /* * casCreateChannel () */ LOCAL struct channel_in_use *casCreateChannel ( -struct client *client, -struct dbAddr *pAddr, -unsigned cid +struct client *client, +struct dbAddr *pAddr, +unsigned cid ) { - static unsigned bucketID; - unsigned *pCID; - struct channel_in_use *pchannel; - int status; + static unsigned bucketID; + unsigned *pCID; + struct channel_in_use *pchannel; + int status; - /* get block off free list if possible */ - pchannel = (struct channel_in_use *) - freeListCalloc(rsrvChanFreeList); - if (!pchannel) { - return NULL; - } - ellInit(&pchannel->eventq); - tsStampGetCurrent(&pchannel->time_at_creation); - pchannel->addr = *pAddr; - pchannel->client = client; - /* - * bypass read only warning - */ - pCID = (unsigned *) &pchannel->cid; - *pCID = cid; + /* get block off free list if possible */ + pchannel = (struct channel_in_use *) + freeListCalloc(rsrvChanFreeList); + if (!pchannel) { + return NULL; + } + ellInit(&pchannel->eventq); + tsStampGetCurrent(&pchannel->time_at_creation); + pchannel->addr = *pAddr; + pchannel->client = client; + /* + * bypass read only warning + */ + pCID = (unsigned *) &pchannel->cid; + *pCID = cid; - /* - * allocate a server id and enter the channel pointer - * in the table - * - * NOTE: This detects the case where the PV id wraps - * around and we attempt to have two resources on the same id. - * The lock is applied here because on some architectures the - * ++ operator isnt atomic. - */ - LOCK_CLIENTQ; + /* + * allocate a server id and enter the channel pointer + * in the table + * + * NOTE: This detects the case where the PV id wraps + * around and we attempt to have two resources on the same id. + * The lock is applied here because on some architectures the + * ++ operator isnt atomic. + */ + LOCK_CLIENTQ; - do { - /* - * bypass read only warning - */ - pCID = (unsigned *) &pchannel->sid; - *pCID = bucketID++; + do { + /* + * bypass read only warning + */ + pCID = (unsigned *) &pchannel->sid; + *pCID = bucketID++; - /* - * Verify that this id is not in use - */ - status = bucketAddItemUnsignedId ( - pCaBucket, - &pchannel->sid, - pchannel); - } while (status != S_bucket_success); + /* + * Verify that this id is not in use + */ + status = bucketAddItemUnsignedId ( + pCaBucket, + &pchannel->sid, + pchannel); + } while (status != S_bucket_success); - UNLOCK_CLIENTQ; + UNLOCK_CLIENTQ; - if(status!=S_bucket_success){ - freeListFree(rsrvChanFreeList, pchannel); - errMessage (status, "Unable to allocate server id"); - return NULL; - } + if(status!=S_bucket_success){ + freeListFree(rsrvChanFreeList, pchannel); + errMessage (status, "Unable to allocate server id"); + return NULL; + } - semMutexMustTake(client->addrqLock); - ellAdd(&client->addrq, &pchannel->node); - semMutexGive(client->addrqLock); + semMutexMustTake(client->addrqLock); + ellAdd(&client->addrq, &pchannel->node); + semMutexGive(client->addrqLock); - return pchannel; + return pchannel; } /* @@ -979,41 +949,41 @@ unsigned cid */ LOCAL void access_rights_reply(struct channel_in_use *pciu) { - struct client *pclient; - caHdr *reply; - unsigned ar; - int v41; + struct client *pclient; + caHdr *reply; + unsigned ar; + int v41; - pclient = pciu->client; + pclient = pciu->client; - assert(pclient != prsrv_cast_client); + assert(pclient != prsrv_cast_client); - /* - * noop if this is an old client - */ - v41 = CA_V41(CA_PROTOCOL_VERSION,pclient->minor_version_number); - if(!v41){ - return; - } + /* + * noop if this is an old client + */ + v41 = CA_V41(CA_PROTOCOL_VERSION,pclient->minor_version_number); + if(!v41){ + return; + } - ar = 0; /* none */ - if(asCheckGet(pciu->asClientPVT)){ - ar |= CA_PROTO_ACCESS_RIGHT_READ; - } - if(rsrvCheckPut(pciu)){ - ar |= CA_PROTO_ACCESS_RIGHT_WRITE; - } + ar = 0; /* none */ + if(asCheckGet(pciu->asClientPVT)){ + ar |= CA_PROTO_ACCESS_RIGHT_READ; + } + if(rsrvCheckPut(pciu)){ + ar |= CA_PROTO_ACCESS_RIGHT_WRITE; + } - SEND_LOCK(pclient); - reply = (caHdr *)ALLOC_MSG(pclient, 0); - assert(reply); + SEND_LOCK(pclient); + reply = (caHdr *)ALLOC_MSG(pclient, 0); + assert(reply); - *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); + *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); } /* @@ -1024,53 +994,53 @@ LOCAL void access_rights_reply(struct channel_in_use *pciu) */ LOCAL void casAccessRightsCB(ASCLIENTPVT ascpvt, asClientStatus type) { - struct client *pclient; - struct channel_in_use *pciu; - struct event_ext *pevext; + struct client *pclient; + struct channel_in_use *pciu; + struct event_ext *pevext; - pciu = asGetClientPvt(ascpvt); - assert(pciu); + pciu = asGetClientPvt(ascpvt); + assert(pciu); - pclient = pciu->client; - assert(pclient); + pclient = pciu->client; + assert(pclient); - if(pclient == prsrv_cast_client){ - return; - } + if(pclient == prsrv_cast_client){ + return; + } - switch(type) - { - case asClientCOAR: + switch(type) + { + case asClientCOAR: - access_rights_reply(pciu); + access_rights_reply(pciu); - /* - * Update all event call backs - */ - semMutexMustTake(pclient->eventqLock); - for (pevext = (struct event_ext *) ellFirst(&pciu->eventq); - pevext; - pevext = (struct event_ext *) ellNext(&pevext->node)){ - int readAccess; + /* + * Update all event call backs + */ + semMutexMustTake(pclient->eventqLock); + for (pevext = (struct event_ext *) ellFirst(&pciu->eventq); + pevext; + pevext = (struct event_ext *) ellNext(&pevext->node)){ + int readAccess; - readAccess = asCheckGet(pciu->asClientPVT); + 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); - } - } - semMutexGive(pclient->eventqLock); + 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); + } + } + semMutexGive(pclient->eventqLock); - break; + break; - default: - break; - } + default: + break; + } } /* @@ -1081,178 +1051,187 @@ caHdr *mp, struct client *client ) { - int v42; - int status; - struct channel_in_use *pciu; + 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; + /* + * 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; + 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; - } + status = db_name_to_addr( + (char *)(mp+1), + &tmp_addr); + if (status) { + return RSRV_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 { - semMutexMustTake(prsrv_cast_client->addrqLock); - /* - * clients which dont claim their - * channel in use block prior to - * timeout must reconnect - */ - pciu = MPTOPCIU(mp); - if(!pciu){ - errlogPrintf("CAS: client timeout disconnect id=%d\n", - mp->m_cid); - semMutexGive(prsrv_cast_client->addrqLock); + 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_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) { - errlogPrintf("CAS: duplicate claim disconnect id=%d\n", - mp->m_cid); - semMutexGive(prsrv_cast_client->addrqLock); + send_err(mp, + ECA_ALLOCMEM, + client, + RECORD_NAME(&tmp_addr)); + SEND_UNLOCK(client); + return RSRV_ERROR; + } + } + else { + semMutexMustTake(prsrv_cast_client->addrqLock); + /* + * clients which dont claim their + * channel in use block prior to + * timeout must reconnect + */ + pciu = MPTOPCIU(mp); + if(!pciu){ + errlogPrintf("CAS: client timeout disconnect id=%d\n", + mp->m_cid); + semMutexGive(prsrv_cast_client->addrqLock); SEND_LOCK(client); - send_err( - mp, - ECA_INTERNAL, - client, - "duplicate claim in old connect protocol"); - SEND_UNLOCK(client); - return ERROR; - } + send_err( + mp, + ECA_INTERNAL, + client, + "old connect protocol timed out"); + SEND_UNLOCK(client); + return RSRV_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); - semMutexGive(prsrv_cast_client->addrqLock); + /* + * duplicate claim message are unacceptable + * (so we disconnect the client) + */ + if (pciu->client!=prsrv_cast_client) { + errlogPrintf("CAS: duplicate claim disconnect id=%d\n", + mp->m_cid); + semMutexGive(prsrv_cast_client->addrqLock); + SEND_LOCK(client); + send_err( + mp, + ECA_INTERNAL, + client, + "duplicate claim in old connect protocol"); + SEND_UNLOCK(client); + return RSRV_ERROR; + } - semMutexMustTake(prsrv_cast_client->addrqLock); - pciu->client = client; - ellAdd(&client->addrq, &pciu->node); - semMutexGive(prsrv_cast_client->addrqLock); - } + /* + * 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); + semMutexGive(prsrv_cast_client->addrqLock); + + semMutexMustTake(prsrv_cast_client->addrqLock); + pciu->client = client; + ellAdd(&client->addrq, &pciu->node); + semMutexGive(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); + /* + * 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 RSRV_ERROR; + } - v42 = CA_V42( - CA_PROTOCOL_VERSION, - client->minor_version_number); + /* + * store ptr to channel in use block + * in access security private + */ + asPutClientPvt(pciu->asClientPVT, pciu); - /* - * 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, + 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; - } + SEND_UNLOCK(client); + return RSRV_ERROR; + } - if(v42){ - caHdr *claim_reply; + if(v42){ + caHdr *claim_reply; - SEND_LOCK(client); - claim_reply = (caHdr *) ALLOC_MSG(client, 0); - assert (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_dataType = 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; + *claim_reply = nill_msg; + claim_reply->m_cmmd = CA_PROTO_CLAIM_CIU; + claim_reply->m_dataType = pciu->addr.dbr_field_type; + if (pciu->addr.no_elements<0) { + claim_reply->m_count = 0; + } + else if (pciu->addr.no_elements>0xffff) { + claim_reply->m_count = 0xffff; + } + else { + claim_reply->m_count = (ca_uint16_t) 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); - ) + DBLOCK(3, + printf ("claim_cui reply:\n"); + log_header (NULL, client, claim_reply, 0); + ) - END_MSG(client); - SEND_UNLOCK(client); - } - return OK; + END_MSG(client); + SEND_UNLOCK(client); + } + return RSRV_OK; } @@ -1263,40 +1242,40 @@ struct client *client */ LOCAL void write_notify_call_back(PUTNOTIFY *ppn) { - struct client *pclient; - struct channel_in_use *pciu; + 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); + /* + * 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){ - errlogPrintf("Double DB put notify call back!!\n"); - return; - } + if(!pciu->pPutNotify->busy){ + errlogPrintf("Double DB put notify call back!!\n"); + return; + } - pclient = pciu->client; + 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). - */ - semMutexMustTake(pclient->putNotifyLock); - ellAdd(&pclient->putNotifyQue, &pciu->pPutNotify->node); - semMutexGive(pclient->putNotifyLock); + /* + * independent lock used here in order to + * avoid any possibility of blocking + * the database (or indirectly blocking + * one client on another client). + */ + semMutexMustTake(pclient->putNotifyLock); + ellAdd(&pclient->putNotifyQue, &pciu->pPutNotify->node); + semMutexGive(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); + /* + * 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); } @@ -1307,101 +1286,100 @@ LOCAL void write_notify_call_back(PUTNOTIFY *ppn) */ void write_notify_reply(void *pArg) { - RSRVPUTNOTIFY *ppnb; - struct client *pClient; - caHdr *preply; + RSRVPUTNOTIFY *ppnb; + struct client *pClient; + caHdr *preply; - pClient = pArg; + 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). - */ - semMutexMustTake(pClient->putNotifyLock); - ppnb = (RSRVPUTNOTIFY *)ellGet(&pClient->putNotifyQue); - semMutexGive(pClient->putNotifyLock); - /* - * break to loop exit - */ - if(!ppnb){ - break; - } + 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). + */ + semMutexMustTake(pClient->putNotifyLock); + ppnb = (RSRVPUTNOTIFY *)ellGet(&pClient->putNotifyQue); + semMutexGive(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 - */ - errlogPrintf("CA server corrupted - put call back(s) discarded\n"); - 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; - } + /* + * aquire sufficient output buffer + */ + preply = ALLOC_MSG(pClient, 0); + if (!preply) { + /* + * inability to aquire buffer space + * Indicates corruption + */ + errlogPrintf("CA server corrupted - put call back(s) discarded\n"); + 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; - } + /* commit the message */ + END_MSG(pClient); + ppnb->busy = FALSE; + } - cas_send_msg(pClient,FALSE); + cas_send_msg(pClient,FALSE); - SEND_UNLOCK(pClient); + SEND_UNLOCK(pClient); - /* - * wakeup the TCP thread if it is waiting for a cb to complete - */ + /* + * wakeup the TCP thread if it is waiting for a cb to complete + */ semBinaryGive(pClient->blockSem); } /* * putNotifyErrorReply */ -LOCAL void putNotifyErrorReply(struct client *client, caHdr *mp, int statusCA) +LOCAL void putNotifyErrorReply (struct client *client, caHdr *mp, int statusCA) { - caHdr *preply; + caHdr *preply; - SEND_LOCK(client); - preply = ALLOC_MSG(client, 0); - if(!preply){ - errlogPrintf("Fatal Error:%s, %d\n", - __FILE__, - __LINE__); - threadSuspend(threadGetIdSelf()); - } + SEND_LOCK (client); + preply = ALLOC_MSG (client, 0); + if (!preply) { + errlogPrintf ("%s at %d: should always get sufficent space for put notify error reply\n", + __FILE__, __LINE__); + return; + } - *preply = *mp; - /* - * the cid field abused to contain status - * during put cb replies - */ - preply->m_cid = statusCA; - END_MSG(client); - SEND_UNLOCK(client); + *preply = *mp; + /* + * the cid field abused to contain status + * during put cb replies + */ + preply->m_cid = statusCA; + END_MSG(client); + SEND_UNLOCK(client); } /* @@ -1412,106 +1390,103 @@ caHdr *mp, struct client *client ) { - unsigned long size; - int status; - struct channel_in_use *pciu; + unsigned long size; + int status; + struct channel_in_use *pciu; - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - return ERROR; - } + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return RSRV_ERROR; + } - if (mp->m_dataType > LAST_BUFFER_TYPE) { - putNotifyErrorReply(client, mp, ECA_BADTYPE); - return ERROR; - } + if (mp->m_dataType > LAST_BUFFER_TYPE) { + putNotifyErrorReply (client, mp, ECA_BADTYPE); + return RSRV_ERROR; + } - if(!rsrvCheckPut(pciu)){ - putNotifyErrorReply(client, mp, ECA_NOWTACCESS); - return OK; - } + if(!rsrvCheckPut(pciu)){ + putNotifyErrorReply (client, mp, ECA_NOWTACCESS); + return RSRV_OK; + } - size = dbr_size_n(mp->m_dataType, mp->m_count); + size = dbr_size_n (mp->m_dataType, mp->m_count); - if(pciu->pPutNotify){ + if (pciu->pPutNotify) { - /* - * serialize concurrent put notifies - */ - while(pciu->pPutNotify->busy){ - status = semBinaryTakeTimeout(client->blockSem,60.0); - if(status != semTakeOK && 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; - } - } + /* + * serialize concurrent put notifies + */ + while(pciu->pPutNotify->busy){ + status = semBinaryTakeTimeout(client->blockSem,60.0); + if(status != semTakeOK && 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 RSRV_OK; + } + } - /* - * if not busy then free the current - * block if it is to small - */ - if(pciu->pPutNotify->valueSizepPutNotify); - pciu->pPutNotify = NULL; - } - } + /* + * 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; - } + /* + * 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 RSRV_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; + 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_dataType]) - ( mp + 1, - pciu->pPutNotify->dbPutNotify.pbuffer, - FALSE, /* net -> host format */ - mp->m_count); + /* use type as index into conversion jumptable */ + (* cac_dbr_cvrt[mp->m_dataType]) + ( mp + 1, + pciu->pPutNotify->dbPutNotify.pbuffer, + FALSE, /* net -> host format */ + mp->m_count); #else - memcpy(pciu->pPutNotify->dbPutNotify.pbuffer, (void *)(mp+1), size); + memcpy(pciu->pPutNotify->dbPutNotify.pbuffer, (void *)(mp+1), size); #endif - status = dbPutNotifyMapType(&pciu->pPutNotify->dbPutNotify, mp->m_dataType); - if(status){ - putNotifyErrorReply(client, mp, ECA_PUTFAIL); - pciu->pPutNotify->busy = FALSE; - return OK; - } + status = dbPutNotifyMapType(&pciu->pPutNotify->dbPutNotify, mp->m_dataType); + if(status){ + putNotifyErrorReply (client, mp, ECA_PUTFAIL); + pciu->pPutNotify->busy = FALSE; + return RSRV_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; + 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 RSRV_OK; } /* @@ -1519,125 +1494,106 @@ struct client *client * event_add_action() * */ -LOCAL int event_add_action( -caHdr *mp, -struct client *client -) +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; + struct monops *pmo = (struct monops *) mp; + struct channel_in_use *pciu; + struct event_ext *pevext; - pciu = MPTOPCIU(mp); - if(!pciu){ - logBadId(client, mp); - return ERROR; - } + pciu = MPTOPCIU(mp); + if(!pciu){ + logBadId(client, mp); + return RSRV_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; - } + pevext = (struct event_ext *) freeListCalloc (rsrvEventFreeList); + if (!pevext) { + SEND_LOCK(client); + send_err( + mp, + ECA_ALLOCMEM, + client, + RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return RSRV_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); + /* 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_dataType, mp->m_count); - pevext->mask = pmo->m_info.m_mask; + pevext->msg = *mp; + pevext->pciu = pciu; + pevext->send_lock = TRUE; + pevext->size = dbr_size_n(mp->m_dataType, mp->m_count); + pevext->mask = pmo->m_info.m_mask; - semMutexMustTake(client->eventqLock); - ellAdd( &pciu->eventq, &pevext->node); - semMutexGive(client->eventqLock); + semMutexMustTake(client->eventqLock); + ellAdd( &pciu->eventq, &pevext->node); + semMutexGive(client->eventqLock); - pevext->pdbev = (struct event_block *)(pevext+1); + pevext->pdbev = db_add_event (client->evuser, &pciu->addr, + read_reply, pevext, pevext->mask); + if (pevext->pdbev == NULL) { + SEND_LOCK(client); + send_err (mp, ECA_ADDFAIL, client, RECORD_NAME(&pciu->addr)); + SEND_UNLOCK(client); + return RSRV_ERROR; + } - 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). + */ - /* - * 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); - 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); + } - /* - * 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; + return RSRV_OK; } /* - * clear_channel_reply() + * clear_channel_reply() */ LOCAL int clear_channel_reply( caHdr *mp, @@ -1657,7 +1613,7 @@ struct client *client pciu = MPTOPCIU(mp); if(pciu?pciu->client!=client:TRUE){ logBadId(client, mp); - return ERROR; + return RSRV_ERROR; } /* @@ -1678,20 +1634,19 @@ struct client *client break; } - if(pevext->pdbev){ - status = db_cancel_event(pevext->pdbev); - assert(status == OK); + if (pevext->pdbev) { + db_cancel_event (pevext->pdbev); } freeListFree(rsrvEventFreeList, pevext); } status = db_flush_extra_labor_event(client->evuser); if (status) { - SEND_LOCK(client); - send_err(mp, ECA_INTERNAL, client, + SEND_LOCK(client); + send_err(mp, ECA_INTERNAL, client, "extra labor event didnt flush"); - SEND_UNLOCK(client); - return ERROR; + SEND_UNLOCK(client); + return RSRV_ERROR; } if (pciu->pPutNotify) { @@ -1705,7 +1660,7 @@ struct client *client reply = (caHdr *) ALLOC_MSG(client, 0); if (!reply) { SEND_UNLOCK(client); - return ERROR; + return RSRV_ERROR; } *reply = *mp; @@ -1734,28 +1689,24 @@ struct client *client UNLOCK_CLIENTQ; freeListFree(rsrvChanFreeList, pciu); - return OK; + return RSRV_OK; } /* * - * event_cancel_reply() + * 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 int event_cancel_reply( - caHdr *mp, - struct client *client - ) +LOCAL int event_cancel_reply (caHdr *mp, struct client *client) { struct channel_in_use *pciu; caHdr *reply; struct event_ext *pevext; - int status; /* * @@ -1765,7 +1716,7 @@ LOCAL int event_cancel_reply( pciu = MPTOPCIU(mp); if (pciu?pciu->client!=client:TRUE) { logBadId(client, mp); - return ERROR; + return RSRV_ERROR; } /* @@ -1790,21 +1741,14 @@ LOCAL int event_cancel_reply( SEND_LOCK(client); send_err(mp, ECA_BADMONID, client, RECORD_NAME(&pciu->addr)); SEND_UNLOCK(client); - return ERROR; + return RSRV_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; - } + if (pevext->pdbev) { + db_cancel_event (pevext->pdbev); } /* @@ -1814,7 +1758,7 @@ LOCAL int event_cancel_reply( reply = (caHdr *) ALLOC_MSG(client, 0); if (!reply) { SEND_UNLOCK(client); - return ERROR; + return RSRV_ERROR; } *reply = pevext->msg; reply->m_postsize = 0; @@ -1824,64 +1768,63 @@ LOCAL int event_cancel_reply( freeListFree (rsrvEventFreeList, pevext); - return OK; + return RSRV_OK; } /* - * read_sync_reply() + * read_sync_reply() */ LOCAL int read_sync_reply( caHdr *mp, struct client *client ) { - caHdr *reply; + caHdr *reply; - SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, 0); + SEND_LOCK(client); + reply = (caHdr *) ALLOC_MSG(client, 0); if (!reply) { SEND_UNLOCK(client); - return ERROR; + return RSRV_ERROR; } - *reply = *mp; + *reply = *mp; - END_MSG(client); + END_MSG(client); - SEND_UNLOCK(client); + SEND_UNLOCK(client); - return OK; + return RSRV_OK; } -/* +/* * search_fail_reply() * - * Only when requested by the client - * send search failed reply + * Only when requested by the client + * send search failed reply */ -LOCAL void search_fail_reply( -caHdr *mp, -struct client *client -) +LOCAL void search_fail_reply (caHdr *mp, struct client *client) { - caHdr *reply; + caHdr *reply; - SEND_LOCK(client); - reply = (caHdr *) ALLOC_MSG(client, 0); - if (!reply) { - threadSuspend(threadGetIdSelf()); - } - *reply = *mp; - reply->m_cmmd = CA_PROTO_NOT_FOUND; - reply->m_postsize = 0; + SEND_LOCK(client); + reply = (caHdr *) ALLOC_MSG(client, 0); + if (!reply) { + errlogPrintf ("%s at %d: should always get sufficent space for search fail reply\n", + __FILE__, __LINE__); + return; + } + *reply = *mp; + reply->m_cmmd = CA_PROTO_NOT_FOUND; + reply->m_postsize = 0; - END_MSG(client); - SEND_UNLOCK(client); + END_MSG(client); + SEND_UNLOCK(client); } /* - * search_reply() + * search_reply() */ LOCAL int search_reply( caHdr *mp, @@ -1891,15 +1834,28 @@ LOCAL int search_reply( struct dbAddr tmp_addr; caHdr *search_reply; unsigned short *pMinorVersion; + const char *pName = (const char *)(mp+1); int status; unsigned sid; - unsigned long count; + ca_uint16_t count; ca_uint16_t type; int spaceAvailOnFreeList; + + /* + * check the sanity of the message + */ + if (mp->m_postsize<=1) { + log_header ("empty PV name in UDP search request?", client, mp, 0); + return RSRV_OK; + } + if (pName+mp->m_postsize-1 != '\0') { + log_header ("unterminated PV name in UDP search request?", client, mp, 0); + return RSRV_OK; + } /* Exit quickly if channel not on this node */ - status = db_name_to_addr((char *) (mp+1), &tmp_addr); - if (status < 0) { + status = db_name_to_addr (pName, &tmp_addr); + if (status) { DLOG (2, "CAS: Lookup for channel \"%s\" failed\n", (int)(mp+1), NULL, @@ -1909,24 +1865,23 @@ LOCAL int search_reply( NULL); if (mp->m_dataType == DOREPLY) search_fail_reply(mp, client); - return OK; + return RSRV_OK; } /* - * stop further use of server if max block drops - * below MAX_BLOCK_THRESHOLD + * stop further use of server if memory becomes scarse */ spaceAvailOnFreeList = freeListItemsAvail(rsrvClientFreeList)>0 && freeListItemsAvail(rsrvChanFreeList)>0 && freeListItemsAvail(rsrvEventFreeList)>0; - if (casBelowMaxBlockThresh && !spaceAvailOnFreeList) { + if (!casSufficentSpaceInPool && !spaceAvailOnFreeList) { SEND_LOCK(client); send_err(mp, ECA_ALLOCMEM, client, "Server memory exhausted"); SEND_UNLOCK(client); - return OK; + return RSRV_OK; } /* @@ -1944,7 +1899,7 @@ LOCAL int search_reply( type = ca_server_port; } else { - struct channel_in_use *pchannel; + struct channel_in_use *pchannel; pchannel = casCreateChannel ( client, @@ -1957,10 +1912,18 @@ LOCAL int search_reply( client, RECORD_NAME(&tmp_addr)); SEND_UNLOCK(client); - return OK; + return RSRV_OK; } sid = pchannel->sid; - count = tmp_addr.no_elements; + if (tmp_addr.no_elements<0) { + count = 0; + } + else if (tmp_addr.no_elements>0xffff) { + count = 0xffff; + } + else { + count = (ca_uint16_t) tmp_addr.no_elements; + } type = (ca_uint16_t) tmp_addr.dbr_field_type; } @@ -1970,7 +1933,7 @@ LOCAL int search_reply( ALLOC_MSG(client, sizeof(*pMinorVersion)); if (!search_reply) { SEND_UNLOCK(client); - return ERROR; + return RSRV_ERROR; } *search_reply = *mp; @@ -1992,32 +1955,28 @@ LOCAL int search_reply( END_MSG(client); SEND_UNLOCK(client); - return OK; + return RSRV_OK; } /* - * - * cac_send_heartbeat() - * - * lock must be applied while in this routine + * cac_send_heartbeat() + * **** lock must be applied while in this routine **** */ -void cas_send_heartbeat( -struct client *pc -) +void cas_send_heartbeat (struct client *pc) { - caHdr *reply; - - reply = (caHdr *) ALLOC_MSG(pc, 0); - if(!reply){ - threadSuspend(threadGetIdSelf()); - } - - *reply = nill_msg; - reply->m_cmmd = CA_PROTO_NOOP; - - END_MSG(pc); + caHdr *reply; + reply = (caHdr *) ALLOC_MSG(pc, 0); + if (!reply) { return; + } + + *reply = nill_msg; + reply->m_cmmd = CA_PROTO_NOOP; + + END_MSG(pc); + + return; } typedef int (*pProtoStub) (caHdr *mp, struct client *client); @@ -2037,15 +1996,15 @@ LOCAL const pProtoStub tcpJumpTable[] = bad_tcp_cmd_action, events_off_action, events_on_action, - read_sync_reply, + read_sync_reply, bad_tcp_cmd_action, - clear_channel_reply, + clear_channel_reply, bad_tcp_cmd_action, bad_tcp_cmd_action, read_action, bad_tcp_cmd_action, bad_tcp_cmd_action, - claim_ciu_action, + claim_ciu_action, write_notify_action, client_name_action, host_name_action, @@ -2068,7 +2027,7 @@ LOCAL const pProtoStub udpJumpTable[] = bad_udp_cmd_action, bad_udp_cmd_action, bad_udp_cmd_action, - search_reply, + search_reply, bad_udp_cmd_action, bad_udp_cmd_action, bad_udp_cmd_action, @@ -2096,22 +2055,19 @@ LOCAL const pProtoStub udpJumpTable[] = /* * CAMESSAGE() */ -int camessage( - struct client *client, - struct message_buffer *recv - ) +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; + ca_uint16_t tmp_postsize; + unsigned 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; + return RSRV_ERROR; } } @@ -2124,7 +2080,7 @@ int camessage( /* assert that we have at least a complete caHdr */ if(bytes_left < sizeof(*mp)) - return OK; + return RSRV_OK; mp = (caHdr *) &recv->buf[recv->stk]; @@ -2138,7 +2094,7 @@ int camessage( msgsize = tmp_postsize + sizeof(*mp); if (msgsize > bytes_left) - return OK; + return RSRV_OK; /* Have complete message (header + content) * -> convert the header elements @@ -2153,13 +2109,13 @@ int camessage( nmsg++; if (CASDEBUG > 2) - log_header(NULL, client, mp, nmsg); + log_header (NULL, client, mp, nmsg); if (client==prsrv_cast_client) { if (mp->m_cmmdm_cmmd])(mp, client); - if (status!=OK) { - return ERROR; + if (status!=RSRV_OK) { + return RSRV_ERROR; } } else { @@ -2169,8 +2125,8 @@ int camessage( else { if (mp->m_cmmdm_cmmd])(mp, client); - if (status!=OK) { - return ERROR; + if (status!=RSRV_OK) { + return RSRV_ERROR; } } else { @@ -2182,7 +2138,7 @@ int camessage( bytes_left = recv->cnt - recv->stk; } - return OK; + return RSRV_OK; } /* diff --git a/src/rsrv/camsgtask.c b/src/rsrv/camsgtask.c index a8eb5fa01..4bfe3ba13 100644 --- a/src/rsrv/camsgtask.c +++ b/src/rsrv/camsgtask.c @@ -1,309 +1,143 @@ /* - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 6-88 + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 6-88 * - * Experimental Physics and Industrial Control System (EPICS) + * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory * - * Modification Log: - * ----------------- - * .01 joh 08--88 added broadcast switchover to TCP/IP - * .02 joh 041089 added new event passing - * .03 joh 060791 camsgtask() now returns info about - * partial messages - * .04 joh 071191 changes to recover from UDP port reuse - * by rebooted clients - * .05 joh 110691 print nil recv disconnect message only - * if debug is on - * .06 joh 021192 better diagnostics - * .07 joh 031692 disconnect on bad message - * .08 joh 111892 set TCP buffer size to be synergistic - * with CA buffer size - * .09 joh 111992 moved the event tasks prioity down - * (added new arg to db_start_events()) */ -static char *sccsId = "@(#) $Id$"; #include #include #include #include -#include #include #include "osiSock.h" #include "tsStamp.h" -#include "os_depen.h" #include "osiThread.h" #include "errlog.h" #include "ellLib.h" #include "taskwd.h" #include "db_access.h" #include "server.h" -#include "osiSockResource.h" - /* + * camsgtask() * - * camsgtask() - * - * CA server TCP client task (one spawned for each client) + * CA server TCP client task (one spawned for each client) */ -int camsgtask(sock) -SOCKET sock; +void camsgtask (struct client *client) { - int nchars; - int status; - struct client *client; - int true = TRUE; + int nchars; + int status; + int true = TRUE; + + client->tid = threadGetIdSelf (); - client = NULL; + taskwdInsert (threadGetIdSelf(), NULL, NULL); - /* - * see TCP(4P) this seems to make unsollicited single events much - * faster. I take care of queue up as load increases. - */ - status = setsockopt( - sock, - IPPROTO_TCP, - TCP_NODELAY, - (char *)&true, - sizeof(true)); - if(status == ERROR){ - errlogPrintf("CAS: TCP_NODELAY option set failed\n"); - socket_close(sock); - return ERROR; - } + while (TRUE) { + client->recv.stk = 0; + + nchars = recv (client->sock, &client->recv.buf[client->recv.cnt], + (int)(sizeof(client->recv.buf)-client->recv.cnt), 0); + if (nchars==0){ + if (CASDEBUG>0) { + errlogPrintf ("CAS: nill message disconnect\n"); + } + break; + } + else if (nchars<0) { + int anerrno = SOCKERRNO; + /* + * normal conn lost conditions + */ + if ( (anerrno!=SOCK_ECONNABORTED&& + anerrno!=SOCK_ECONNRESET&& + anerrno!=SOCK_ETIMEDOUT)|| + CASDEBUG>2) { + errlogPrintf ("CAS: client disconnect(errno=%d)\n", anerrno); + } + break; + } - /* - * turn on KEEPALIVE so if the client crashes - * this task will find out and exit - */ - status = setsockopt( - sock, - SOL_SOCKET, - SO_KEEPALIVE, - (char *)&true, - sizeof(true)); - if(status == ERROR){ - errlogPrintf("CAS: SO_KEEPALIVE option set failed\n"); - socket_close(sock); - return ERROR; - } + tsStampGetCurrent (&client->time_at_last_recv); + client->recv.cnt += (unsigned long) nchars; - /* - * some concern that vxWorks will run out of mBuf's - * if this change is made - * - * joh 11-10-98 - */ -#if 0 - /* - * set TCP buffer sizes to be synergistic - * with CA internal buffering - */ - i = MAX_MSG_SIZE; - status = setsockopt( - sock, - SOL_SOCKET, - SO_SNDBUF, - (char *)&i, - sizeof(i)); - if(status < 0){ - errlogPrintf("CAS: SO_SNDBUF set failed\n"); - socket_close(sock); - return ERROR; - } - i = MAX_MSG_SIZE; - status = setsockopt( - sock, - SOL_SOCKET, - SO_RCVBUF, - (char *)&i, - sizeof(i)); - if(status < 0){ - errlogPrintf("CAS: SO_RCVBUF set failed\n"); - socket_close(sock); - return ERROR; - } -#endif + status = camessage (client, &client->recv); + if (status == 0) { + /* + * if there is a partial message + * align it with the start of the buffer + */ + if (client->recv.cnt >= client->recv.stk) { + unsigned bytes_left; + char *pbuf; - /* - * performed in two steps purely for - * historical reasons - */ - client = (struct client *) create_udp_client(NULL); - if (!client) { - errlogPrintf("CAS: client init failed\n"); - socket_close(sock); - return ERROR; - } + bytes_left = client->recv.cnt - client->recv.stk; - taskwdInsert( threadGetIdSelf(), - NULL, - NULL); + pbuf = client->recv.buf; - status = udp_to_tcp(client, sock); - if(status<0){ - errlogPrintf("CAS: TCP convert failed\n"); - free_client(client); - return ERROR; - } - - if(CASDEBUG>0){ - char buf[64]; - ipAddrToA (&client->addr, buf, sizeof(buf)); - errlogPrintf( "CAS: conn req from %s\n", - (int) /* sic */ buf); - } - - LOCK_CLIENTQ; - ellAdd(&clientQ, &client->node); - UNLOCK_CLIENTQ; - - client->evuser = (struct event_user *) db_init_events(); - if (!client->evuser) { - errlogPrintf("CAS: unable to init the event facility\n"); - free_client(client); - return ERROR; - } - status = db_add_extra_labor_event( - client->evuser, - write_notify_reply, - client); - if(status == ERROR){ - errlogPrintf("CAS: unable to setup the event facility\n"); - free_client(client); - return ERROR; - } - status = db_start_events( - client->evuser, - "CAevent", - NULL, - NULL, - 1); /* one priority notch lower */ - if (status == ERROR) { - errlogPrintf("CAS: unable to start the event facility\n"); - free_client(client); - return ERROR; - } - - client->recv.cnt = 0ul; - while (TRUE) { - client->recv.stk = 0; - - nchars = recv( - sock, - &client->recv.buf[client->recv.cnt], - (int)(sizeof(client->recv.buf)-client->recv.cnt), - 0); - if (nchars==0){ - if(CASDEBUG>0){ - errlogPrintf("CAS: nill message disconnect\n"); - } - break; - } - else if(nchars<0){ - long anerrno; - - anerrno = SOCKERRNO; - - /* - * normal conn lost conditions - */ - if( (anerrno!=ECONNABORTED&& - anerrno!=ECONNRESET&& - anerrno!=ETIMEDOUT)|| - CASDEBUG>2){ - - errlogPrintf( - "CAS: client disconnect(errno=%d)\n", - anerrno); - } - - break; - } - - tsStampGetCurrent(&client->time_at_last_recv); - client->recv.cnt += (unsigned long) nchars; - - status = camessage(client, &client->recv); - if(status == OK){ - /* - * if there is a partial message - * align it with the start of the buffer - */ - if (client->recv.cnt >= client->recv.stk) { - unsigned bytes_left; - char *pbuf; - - bytes_left = client->recv.cnt - client->recv.stk; - - pbuf = client->recv.buf; - - /* - * overlapping regions handled - * by memmove - */ - memmove(pbuf, - pbuf + client->recv.stk, - bytes_left); - client->recv.cnt = bytes_left; - } - else{ - client->recv.cnt = 0ul; - } - }else{ + /* + * overlapping regions handled + * properly by memmove + */ + memmove (pbuf, pbuf + client->recv.stk, bytes_left); + client->recv.cnt = bytes_left; + } + else { + client->recv.cnt = 0ul; + } + } + else { char buf[64]; - - client->recv.cnt = 0ul; - - /* - * disconnect when there are severe message errors - */ + + client->recv.cnt = 0ul; + + /* + * disconnect when there are severe message errors + */ ipAddrToA (&client->addr, buf, sizeof(buf)); - errlogPrintf ("CAS: forcing disconnect from %s\n", - /* sic */ (int) buf); - break; - } - - /* - * allow message to batch up if more are comming - */ - status = socket_ioctl(sock, FIONREAD, (int) &nchars); - if (status < 0) { - errlogPrintf("CAS: io ctl err %d\n", - SOCKERRNO); - cas_send_msg(client, TRUE); - } - else if (nchars == 0){ - cas_send_msg(client, TRUE); - } - } - - free_client(client); - - return OK; + errlogPrintf ("CAS: forcing disconnect from %s\n", buf); + break; + } + + /* + * allow message to batch up if more are comming + */ + status = socket_ioctl (client->sock, FIONREAD, &nchars); + if (status < 0) { + errlogPrintf("CAS: io ctl err %d\n", + SOCKERRNO); + cas_send_msg(client, TRUE); + } + else if (nchars == 0){ + cas_send_msg(client, TRUE); + } + } + + destroy_client (client); } diff --git a/src/rsrv/caserverio.c b/src/rsrv/caserverio.c index ff8ff8521..0da00ad77 100644 --- a/src/rsrv/caserverio.c +++ b/src/rsrv/caserverio.c @@ -1,237 +1,206 @@ -/* - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 060791 +/* + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 060791 * - * Experimental Physics and Industrial Control System (EPICS) + * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * Modification Log: - * ----------------- - * .01 joh 071591 log time of last io in the client structure - * .02 joh 091691 use greater than on the DEBUG level test - * .03 joh 110491 improved diagnostics - * .04 joh 021292 improved diagnostics - * .05 joh 022092 improved diagnostics - * .06 joh 031992 improved diagnostics + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory */ -static char *sccsId = "@(#) $Id$"; - #include #include #include #include #include -#include - #include "osiSock.h" #include "tsStamp.h" #include "ellLib.h" #include "errlog.h" #include "server.h" -#include "osiSockResource.h" - /* + * cas_send_msg() * - * cas_send_msg() - * - * (channel access server send message) + * (channel access server send message) */ -void cas_send_msg(pclient, lock_needed) -struct client *pclient; -int lock_needed; +void cas_send_msg (struct client *pclient, int lock_needed) { - int status; + int status; - if(CASDEBUG>2 && pclient->send.stk){ - errlogPrintf( "CAS: Sending a message of %d bytes\n", - pclient->send.stk); - } + if (CASDEBUG>2 && pclient->send.stk) { + errlogPrintf ("CAS: Sending a message of %d bytes\n", pclient->send.stk); + } - if(pclient->disconnect){ - if(CASDEBUG>2){ - errlogPrintf("CAS: msg Discard for sock %d addr %x\n", - pclient->sock, - pclient->addr.sin_addr.s_addr); - } - return; - } + if (pclient->disconnect) { + if (CASDEBUG>2) { + errlogPrintf ("CAS: msg Discard for sock %d addr %x\n", + pclient->sock, pclient->addr.sin_addr.s_addr); + } + return; + } - if(lock_needed){ - SEND_LOCK(pclient); - } + if(lock_needed){ + SEND_LOCK(pclient); + } - if(pclient->send.stk){ + if(pclient->send.stk){ #ifdef CONVERSION_REQUIRED - /* Convert all caHdr into net format. - * The remaining bytes must already be in - * net format, because here we have no clue - * how to convert them. - */ - char *buf; - unsigned long msg_size, num_bytes; - caHdr *mp; + /* Convert all caHdr into net format. + * The remaining bytes must already be in + * net format, because here we have no clue + * how to convert them. + */ + char *buf; + unsigned long msg_size, num_bytes; + caHdr *mp; - - buf = (char *) pclient->send.buf; - num_bytes = pclient->send.stk; + + buf = (char *) pclient->send.buf; + num_bytes = pclient->send.stk; - /* convert only if we have at least a complete caHdr */ - while (num_bytes >= sizeof(caHdr)) - { - mp = (caHdr *) buf; + /* convert only if we have at least a complete caHdr */ + while (num_bytes >= sizeof(caHdr)) + { + mp = (caHdr *) buf; - msg_size = sizeof (caHdr) + mp->m_postsize; + msg_size = sizeof (caHdr) + mp->m_postsize; - DLOG(3,"CAS: sending cmmd %d, postsize %d\n", - mp->m_cmmd, (int)mp->m_postsize, - 0, 0, 0, 0); + DLOG(3,"CAS: sending cmmd %d, postsize %d\n", + mp->m_cmmd, (int)mp->m_postsize, + 0, 0, 0, 0); - /* convert the complete header into host format */ - mp->m_cmmd = htons (mp->m_cmmd); - mp->m_postsize = htons (mp->m_postsize); - mp->m_dataType = htons (mp->m_dataType); - mp->m_count = htons (mp->m_count); - mp->m_cid = htonl (mp->m_cid); - mp->m_available = htonl (mp->m_available); + /* convert the complete header into host format */ + mp->m_cmmd = htons (mp->m_cmmd); + mp->m_postsize = htons (mp->m_postsize); + mp->m_dataType = htons (mp->m_dataType); + mp->m_count = htons (mp->m_count); + mp->m_cid = htonl (mp->m_cid); + mp->m_available = htonl (mp->m_available); - /* get next message: */ - buf += msg_size; - num_bytes -= msg_size; - } + /* get next message: */ + buf += msg_size; + num_bytes -= msg_size; + } #endif - status = sendto( - pclient->sock, - pclient->send.buf, - pclient->send.stk, - NULL, - (struct sockaddr *)&pclient->addr, - sizeof(pclient->addr)); - if( pclient->send.stk != (unsigned)status){ - if(status < 0){ - int anerrno; - char buf[64]; + status = sendto (pclient->sock, pclient->send.buf, pclient->send.stk, 0, + (struct sockaddr *)&pclient->addr, sizeof(pclient->addr)); + if( pclient->send.stk != (unsigned)status) { + if (status < 0) { + int anerrno; + char buf[64]; - anerrno = SOCKERRNO; + anerrno = SOCKERRNO; - ipAddrToA (&pclient->addr, buf, sizeof(buf)); + ipAddrToA (&pclient->addr, buf, sizeof(buf)); - if(pclient->proto == IPPROTO_TCP) { - if( (anerrno!=ECONNABORTED&& - anerrno!=ECONNRESET&& - anerrno!=EPIPE&& - anerrno!=ETIMEDOUT)|| - CASDEBUG>2){ + if(pclient->proto == IPPROTO_TCP) { + if ( (anerrno!=SOCK_ECONNABORTED&& + anerrno!=SOCK_ECONNRESET&& + anerrno!=SOCK_EPIPE&& + anerrno!=SOCK_ETIMEDOUT)|| + CASDEBUG>2){ - errlogPrintf( - "CAS: TCP send to \"%s\" failed because \"%s\"\n", - (int)buf, - (int)SOCKERRSTR(anerrno)); - } - pclient->disconnect = TRUE; - } - else if (pclient->proto == IPPROTO_UDP) { - errlogPrintf( - "CAS: UDP send to \"%s\" failed because \"%s\"\n", - (int)buf, - (int)SOCKERRSTR(anerrno)); - } - else { - assert (0); - } - } - else{ - errlogPrintf( - "CAS: blk sock partial send: req %d sent %d \n", - pclient->send.stk, - status); - } - } + errlogPrintf ( + "CAS: TCP send to \"%s\" failed because \"%s\"\n", + buf, SOCKERRSTR(anerrno)); + } + pclient->disconnect = TRUE; + } + else if (pclient->proto == IPPROTO_UDP) { + errlogPrintf( + "CAS: UDP send to \"%s\" failed because \"%s\"\n", + (int)buf, + (int)SOCKERRSTR(anerrno)); + } + else { + assert (0); + } + } + else{ + errlogPrintf( + "CAS: blk sock partial send: req %d sent %d \n", + pclient->send.stk, + status); + } + } - pclient->send.stk = 0; - tsStampGetCurrent(&pclient->time_at_last_send); - } + pclient->send.stk = 0; + tsStampGetCurrent (&pclient->time_at_last_send); + } + if(lock_needed){ + SEND_UNLOCK(pclient); + } - if(lock_needed){ - SEND_UNLOCK(pclient); - } + DLOG(3, "------------------------------\n\n", 0,0,0,0,0,0); - DLOG(3, "------------------------------\n\n", 0,0,0,0,0,0); - - return; + return; } - - /* * - * cas_alloc_msg() + * cas_alloc_msg() * - * see also ALLOC_MSG()/END_MSG() in server.h + * see also ALLOC_MSG()/END_MSG() in server.h * - * (allocate space in the outgoing message buffer) + * (allocate space in the outgoing message buffer) * - * send lock must be on while in this routine + * send lock must be on while in this routine * - * returns 1) a valid ptr to msg buffer space - * 2) NULL (msg will not fit) - */ -caHdr *cas_alloc_msg(pclient, extsize) -struct client *pclient; /* ptr to per client struct */ -unsigned extsize; /* extension size */ + * returns 1) a valid ptr to msg buffer space + * 2) NULL (msg will not fit) + */ +caHdr *cas_alloc_msg (struct client *pclient, unsigned extsize) { - unsigned msgsize; - unsigned newstack; - - extsize = CA_MESSAGE_ALIGN(extsize); + unsigned msgsize; + unsigned newstack; + + extsize = CA_MESSAGE_ALIGN(extsize); - msgsize = extsize + sizeof(caHdr); + msgsize = extsize + sizeof(caHdr); - newstack = pclient->send.stk + msgsize; - if(newstack > pclient->send.maxstk){ - if(pclient->disconnect){ - pclient->send.stk = 0; - } - else{ - cas_send_msg(pclient, FALSE); - } + newstack = pclient->send.stk + msgsize; + if(newstack > pclient->send.maxstk){ + if(pclient->disconnect){ + pclient->send.stk = 0; + } + else{ + cas_send_msg (pclient, FALSE); + } - newstack = pclient->send.stk + msgsize; + newstack = pclient->send.stk + msgsize; - /* - * If dosnt fit now it never will - */ - if(newstack > pclient->send.maxstk){ - return NULL; - } - } + /* + * If dosnt fit now it never will + */ + if(newstack > pclient->send.maxstk){ + return NULL; + } + } - /* - * it fits END_MSG will push it on the stack - */ - return (caHdr *) &pclient->send.buf[pclient->send.stk]; + /* + * it fits END_MSG will push it on the stack + */ + return (caHdr *) &pclient->send.buf[pclient->send.stk]; } diff --git a/src/rsrv/caservertask.c b/src/rsrv/caservertask.c index 86dee4d96..6e7cd94a4 100644 --- a/src/rsrv/caservertask.c +++ b/src/rsrv/caservertask.c @@ -1,63 +1,44 @@ /* - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 5-88 + * $Id$ * - * Experimental Physics and Industrial Control System (EPICS) + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Experimental Physics and Industrial Control System (EPICS) * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory * - * Modification Log: - * ----------------- - * .01 joh 030891 now saves old client structure for later reuse - * .02 joh 071591 print the delay from the last interaction in - * client_stat(). - * .03 joh 080991 close the socket if task create fails - * .04 joh 090591 updated for v5 vxWorks - * .05 joh 103091 print task id and disconnect state in client_stat() - * .06 joh 112691 dont print client disconnect message unless - * debug is on. - * .07 joh 020592 substitute lstConcat() for lstExtract() to avoid - * replacing the destination list - * .08 joh 021492 cleaned up terminate_one_client() - * .09 joh 022092 print free list statistics in client_stat() - * .10 joh 022592 print more statistics in client_stat() - * .11 joh 073093 added args to taskSpawn for v5.1 vxWorks - * .12 joh 020494 identifies the client in client_stat */ -static char *sccsId = "@(#) $Id$"; - #include #include #include #include #include -#include #include - -#include #include #include "osiSock.h" +#include "osiThread.h" #include "tsStamp.h" #include "errlog.h" #include "ellLib.h" @@ -66,426 +47,621 @@ static char *sccsId = "@(#) $Id$"; #include "envDefs.h" #include "freeList.h" #include "errlog.h" -#include "osiSockResource.h" +#define GLBLSOURCE #include "server.h" -LOCAL int terminate_one_client(struct client *client); -LOCAL void log_one_client(struct client *client, unsigned level); +#define DELETE_TASK(NAME)\ +if(threadNameToId(NAME)!=0)threadDestroy(threadNameToId(NAME)); - /* - * - * req_server() - * - * CA server task - * - * Waits for connections at the CA port and spawns a task to - * handle each of them - * + * create_base_client () */ -int req_server(void) +struct client *create_base_client () { - struct sockaddr_in serverAddr; /* server's address */ - int status; - int i; - - taskwdInsert(threadGetIdSelf(),NULL,NULL); - - ca_server_port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT); - - if (IOC_sock != 0 && IOC_sock != ERROR) - if ((status = socket_close(IOC_sock)) == ERROR) - errlogPrintf( "CAS: Unable to close open master socket\n"); - - /* - * Open the socket. Use ARPA Internet address format and stream - * sockets. Format described in . - */ - if ((IOC_sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR) { - errlogPrintf("CAS: Socket creation error\n"); - threadSuspend(threadGetIdSelf()); - } - - /* Zero the sock_addr structure */ - memset((void *)&serverAddr, 0, sizeof(serverAddr)); - serverAddr.sin_family = AF_INET; - serverAddr.sin_port = htons(ca_server_port); - - /* get server's Internet address */ - if (bind(IOC_sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == ERROR) { - errlogPrintf("CAS: Bind error\n"); - socket_close(IOC_sock); - threadSuspend(threadGetIdSelf()); - } - - /* listen and accept new connections */ - if (listen(IOC_sock, 10) == ERROR) { - errlogPrintf("CAS: Listen error\n"); - socket_close(IOC_sock); - threadSuspend(threadGetIdSelf()); - } - - while (TRUE) { - struct sockaddr sockAddr; - int addLen = sizeof(sockAddr); - - if ((i = accept(IOC_sock, &sockAddr, &addLen)) == ERROR) { - errlogPrintf("CAS: Client accept error was \"%s\"\n", - (int) SOCKERRSTR(SOCKERRNO)); - threadSleep(15.0); - continue; - } else { - threadId id; - id = threadCreate("CAclient", - threadPriorityChannelAccessClient, - threadGetStackSize(threadStackBig), - (THREADFUNC)camsgtask,(void *)i); - if (id==0) { - errlogPrintf("CAS: task creation for new client failed because \"%s\"\n", - (int) strerror(errno)); - threadSleep(15.0); - continue; - } - } - } + struct client *client; + + client = freeListMalloc (rsrvClientFreeList); + if (!client) { + epicsPrintf ("CAS: no space in pool for a new client\n"); + return NULL; + } + + /* + * The following inits to zero done instead of a bfill since the send + * and recv buffers are large and don't need initialization. + * + * memset(client, 0, sizeof(*client)); + */ + + client->blockSem = semBinaryCreate(semEmpty); + if(!client->blockSem){ + freeListFree(rsrvClientFreeList, client); + return NULL; + } + + /* + * user name initially unknown + */ + client->pUserName = malloc(1); + if(!client->pUserName){ + semBinaryDestroy(client->blockSem); + freeListFree(rsrvClientFreeList, client); + return NULL; + } + client->pUserName[0] = '\0'; + + /* + * host name initially unknown + */ + client->pHostName = malloc(1); + if(!client->pHostName){ + semBinaryDestroy(client->blockSem); + free(client->pUserName); + freeListFree(rsrvClientFreeList, client); + return NULL; + } + client->pHostName[0] = '\0'; + + ellInit(&client->addrq); + ellInit(&client->putNotifyQue); + memset((char *)&client->addr, 0, sizeof(client->addr)); + client->tid = 0; + client->sock = SOCKET_ERROR; + client->send.stk = 0ul; + client->send.cnt = 0ul; + client->recv.stk = 0ul; + client->recv.cnt = 0ul; + client->evuser = NULL; + client->disconnect = FALSE; /* for TCP only */ + tsStampGetCurrent(&client->time_at_last_send); + tsStampGetCurrent(&client->time_at_last_recv); + client->proto = IPPROTO_UDP; + client->minor_version_number = CA_UKN_MINOR_VERSION; + + client->send.maxstk = MAX_UDP; + + client->lock = semMutexMustCreate(); + client->putNotifyLock = semMutexMustCreate(); + client->addrqLock = semMutexMustCreate(); + client->eventqLock = semMutexMustCreate(); + + client->recv.maxstk = ETHERNET_MAX_UDP; + return client; } - /* - * - * free_client() - * + * create_client () */ -int free_client(struct client *client) +struct client *create_client (SOCKET sock) { - if (!client) { - return ERROR; - } + static const unsigned slightlyLowerPriority = 1; + int status; + struct client *client; + int true = TRUE; + int addrSize; - /* remove it from the list of clients */ - /* list delete returns no status */ - LOCK_CLIENTQ; - ellDelete(&clientQ, &client->node); - UNLOCK_CLIENTQ; + /* + * see TCP(4P) this seems to make unsolicited single events much + * faster. I take care of queue up as load increases. + */ + status = setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, + (char *)&true, sizeof(true)); + if (status < 0) { + errlogPrintf ("CAS: TCP_NODELAY option set failed\n"); + socket_close (sock); + return NULL; + } + + /* + * turn on KEEPALIVE so if the client crashes + * this task will find out and exit + */ + status = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&true, sizeof(true)); + if (status < 0) { + errlogPrintf ("CAS: SO_KEEPALIVE option set failed\n"); + socket_close (sock); + return NULL; + } + + /* + * some concern that vxWorks will run out of mBuf's + * if this change is made + * + * joh 11-10-98 + */ +#if 0 + /* + * set TCP buffer sizes to be synergistic + * with CA internal buffering + */ + i = MAX_MSG_SIZE; + status = setsockopt (sock, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof(i)); + if (status < 0) { + errlogPrintf ("CAS: SO_SNDBUF set failed\n"); + socket_close (sock); + return NULL; + } + i = MAX_MSG_SIZE; + status = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)&i, sizeof(i)); + if (status < 0) { + errlogPrintf ("CAS: SO_RCVBUF set failed\n"); + socket_close (sock); + return NULL; + } +#endif - terminate_one_client(client); + client = (struct client *) create_base_client (); + if (!client) { + errlogPrintf("CAS: client init failed\n"); + socket_close (sock); + return NULL; + } - freeListFree(rsrvClientFreeList, client); + client->proto = IPPROTO_TCP; + client->send.maxstk = MAX_TCP; + client->recv.maxstk = MAX_TCP; + client->sock = sock; - return OK; + addrSize = sizeof (client->addr); + status = getpeername (sock, (struct sockaddr *)&client->addr, + &addrSize); + if (status < 0) { + epicsPrintf ("CAS: peer address fetch failed\n"); + destroy_client (client); + return NULL; + } + + client->evuser = (struct event_user *) db_init_events(); + if (!client->evuser) { + errlogPrintf ("CAS: unable to init the event facility\n"); + destroy_client (client); + return NULL; + } + + status = db_add_extra_labor_event (client->evuser, write_notify_reply, client); + if (status != DB_EVENT_OK) { + errlogPrintf("CAS: unable to setup the event facility\n"); + destroy_client (client); + return NULL; + } + + status = db_start_events (client->evuser, "CA event", + NULL, NULL, slightlyLowerPriority); + if (status != DB_EVENT_OK) { + errlogPrintf("CAS: unable to start the event facility\n"); + destroy_client (client); + return NULL; + } + + client->recv.cnt = 0ul; + + if (CASDEBUG>0) { + char buf[64]; + ipAddrToA (&client->addr, buf, sizeof(buf)); + errlogPrintf ("CAS: conn req from %s\n", buf); + } + + LOCK_CLIENTQ; + ellAdd (&clientQ, &client->node); + UNLOCK_CLIENTQ; + + return client; } - -/* - * TERMINATE_ONE_CLIENT + +/* + * + * req_server() + * + * CA server task + * + * Waits for connections at the CA port and spawns a task to + * handle each of them + * */ -LOCAL int terminate_one_client(struct client *client) +LOCAL int req_server (void) { - threadId servertid; - SOCKET tmpsock; - int status; - struct event_ext *pevext; - struct channel_in_use *pciu; + struct sockaddr_in serverAddr; /* server's address */ + int status; + SOCKET clientSock; - if (client->proto != IPPROTO_TCP) { - errlogPrintf("CAS: non TCP client delete ignored\n"); - return ERROR; - } + taskwdInsert (threadGetIdSelf(), NULL, NULL); - tmpsock = client->sock; + ca_server_port = caFetchPortConfig (&EPICS_CA_SERVER_PORT, CA_SERVER_PORT); - if(CASDEBUG>0){ - errlogPrintf("CAS: Connection %d Terminated\n", - tmpsock); - } + if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) + if ((status = socket_close(IOC_sock)) < 0) + errlogPrintf( "CAS: Unable to close open master socket\n"); - /* - * exit flow control so the event system will - * shutdown correctly - */ - db_event_flow_ctrl_mode_off(client->evuser); + /* + * Open the socket. Use ARPA Internet address format and stream + * sockets. Format described in . + */ + if ((IOC_sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { + errlogPrintf ("CAS: Socket creation error\n"); + threadSuspend (); + } - /* - * Server task deleted first since close() is not reentrant - */ - servertid = client->tid; - taskwdRemove(servertid); - if (servertid != threadGetIdSelf()){ - if(servertid != 0) { - threadDestroy(servertid); - } - servertid = 0; - } + /* Zero the sock_addr structure */ + memset ((void *)&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons (ca_server_port); - while(TRUE){ - semMutexMustTake(client->addrqLock); - pciu = (struct channel_in_use *) ellGet(&client->addrq); - semMutexGive(client->addrqLock); - if(!pciu){ - break; - } + /* get server's Internet address */ + if (bind(IOC_sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) { + errlogPrintf ("CAS: Bind error\n"); + socket_close (IOC_sock); + threadSuspend (); + } - /* - * put notify in progress needs to be deleted - */ - if(pciu->pPutNotify){ - if(pciu->pPutNotify->busy){ - dbNotifyCancel(&pciu->pPutNotify->dbPutNotify); - } - } + /* listen and accept new connections */ + if (listen(IOC_sock, 10) < 0) { + errlogPrintf ("CAS: Listen error\n"); + socket_close (IOC_sock); + threadSuspend (); + } - while (TRUE){ - /* - * AS state change could be using this list - */ - semMutexMustTake(client->eventqLock); - pevext = (struct event_ext *) ellGet(&pciu->eventq); - semMutexGive(client->eventqLock); - if(!pevext){ - break; - } + while (TRUE) { + struct sockaddr sockAddr; + int addLen = sizeof(sockAddr); - if(pevext->pdbev){ - status = db_cancel_event(pevext->pdbev); - assert(status == OK); - } - freeListFree(rsrvEventFreeList, pevext); - } - status = db_flush_extra_labor_event(client->evuser); - assert(status==OK); - if(pciu->pPutNotify){ - free(pciu->pPutNotify); - } - LOCK_CLIENTQ; - status = bucketRemoveItemUnsignedId ( - pCaBucket, - &pciu->sid); - UNLOCK_CLIENTQ; - if(status != S_bucket_success){ - errPrintf ( - status, - __FILE__, - __LINE__, - "Bad id=%d at close", - pciu->sid); - } - status = asRemoveClient(&pciu->asClientPVT); - if(status!=0 && status != S_asLib_asNotActive){ - printf("And the status is %x \n", status); - errPrintf(status, __FILE__, __LINE__, "asRemoveClient"); - } + if ((clientSock = accept(IOC_sock, &sockAddr, &addLen)) == SOCKET_ERROR) { + errlogPrintf("CAS: Client accept error was \"%s\"\n", + (int) SOCKERRSTR(SOCKERRNO)); + threadSleep(15.0); + continue; + } else { + threadId id; + struct client *pClient; - /* - * place per channel block onto the - * free list - */ - freeListFree (rsrvChanFreeList, pciu); - } - - if (client->evuser) { - status = db_close_events(client->evuser); - if (status == ERROR) - threadSuspend(threadGetIdSelf()); - } - if (socket_close(tmpsock) == ERROR) /* close socket */ - errlogPrintf("CAS: Unable to close socket\n"); - - semMutexDestroy(client->eventqLock); - - semMutexDestroy(client->addrqLock); - - semMutexDestroy(client->putNotifyLock); - - semMutexDestroy(client->lock); - - semBinaryDestroy(client->blockSem); - - if(client->pUserName){ - free(client->pUserName); - } - - if(client->pHostName){ - free(client->pHostName); - } - - client->minor_version_number = CA_UKN_MINOR_VERSION; - - return OK; + pClient = create_client (clientSock); + if (!pClient) { + errlogPrintf("CAS: unable to create new client because \"%s\"\n", + strerror(errno)); + threadSleep(15.0); + continue; + } + id = threadCreate ("CAclient", threadPriorityChannelAccessClient, + threadGetStackSize (threadStackBig), camsgtask, (void *)pClient); + if (id==0) { + destroy_client (pClient); + errlogPrintf("CAS: task creation for new client failed because \"%s\"\n", + strerror(errno)); + threadSleep(15.0); + continue; + } + } + } } - /* - * client_stat() + * rsrv_init() + */ +int rsrv_init() +{ + clientQlock = semMutexMustCreate(); + + ellInit (&clientQ); + freeListInitPvt (&rsrvClientFreeList, sizeof(struct client), 8); + freeListInitPvt (&rsrvChanFreeList, sizeof(struct channel_in_use), 512); + freeListInitPvt (&rsrvEventFreeList, sizeof(struct event_ext), 512); + ellInit (&beaconAddrList); + prsrv_cast_client = NULL; + pCaBucket = NULL; + + threadCreate ("CAtcp", + threadPriorityChannelAccessServer, + threadGetStackSize(threadStackMedium), + (THREADFUNC)req_server,0); + + threadCreate ("CAudp", + threadPriorityChannelAccessServer-1, + threadGetStackSize(threadStackMedium), + (THREADFUNC)cast_server,0); + + return RSRV_OK; +} + +/* + * client_stat() */ int client_stat(unsigned level) { - printf ("\"client_stat\" has been replaced by \"casr\"\n"); - return ellCount(&clientQ); + printf ("\"client_stat\" has been replaced by \"casr\"\n"); + return ellCount(&clientQ); } /* - * casr() + * log_one_client () + */ +LOCAL void log_one_client (struct client *client, unsigned level) +{ + int i; + struct channel_in_use *pciu; + char *pproto; + double send_delay; + double recv_delay; + unsigned long bytes_reserved; + char *state[] = {"up", "down"}; + TS_STAMP current; + char clientHostName[256]; + + ipAddrToA (&client->addr, clientHostName, sizeof(clientHostName)); + + if(client->proto == IPPROTO_UDP){ + pproto = "UDP"; + } + else if(client->proto == IPPROTO_TCP){ + pproto = "TCP"; + } + else{ + pproto = "UKN"; + } + + tsStampGetCurrent(¤t); + send_delay = tsStampDiffInSeconds(¤t,&client->time_at_last_send); + recv_delay = tsStampDiffInSeconds(¤t,&client->time_at_last_recv); + + printf( "%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)); + if (level>=1) { + printf ("\tTask Id=%p, Protocol=%3s, Socket FD=%d\n", client->tid, + pproto, client->sock); + printf( + "\tSecs since last send %6.2f, Secs since last receive %6.2f\n", + send_delay, recv_delay); + printf( + "\tUnprocessed request bytes=%lu, Undelivered response bytes=%lu, State=%s\n", + client->send.stk, + client->recv.cnt - client->recv.stk, + state[client->disconnect?1:0]); + } + + if (level>=2u) { + bytes_reserved = 0; + bytes_reserved += sizeof(struct client); + + semMutexMustTake(client->addrqLock); + pciu = (struct channel_in_use *) client->addrq.node.next; + while (pciu){ + bytes_reserved += sizeof(struct channel_in_use); + bytes_reserved += sizeof(struct event_ext)*ellCount(&pciu->eventq); + if(pciu->pPutNotify){ + bytes_reserved += sizeof(*pciu->pPutNotify); + bytes_reserved += pciu->pPutNotify->valueSize; + } + pciu = (struct channel_in_use *) ellNext(&pciu->node); + } + semMutexGive(client->addrqLock); + printf( "\t%ld bytes allocated\n", bytes_reserved); + + + semMutexMustTake(client->addrqLock); + pciu = (struct channel_in_use *) client->addrq.node.next; + i=0; + while (pciu){ + printf( "\t%s(%d%c%c)", + pciu->addr.precord->name, + ellCount(&pciu->eventq), + asCheckGet(pciu->asClientPVT)?'r':'-', + rsrvCheckPut(pciu)?'w':'-'); + pciu = (struct channel_in_use *) ellNext(&pciu->node); + if( ++i % 3 == 0){ + printf("\n"); + } + } + semMutexGive(client->addrqLock); + printf("\n"); + } + + if (level >= 3u) { + printf( "\tSend Lock\n"); + semMutexShow(client->lock,1); + printf( "\tPut Notify Lock\n"); + semMutexShow (client->putNotifyLock,1); + printf( "\tAddress Queue Lock\n"); + semMutexShow (client->addrqLock,1); + printf( "\tEvent Queue Lock\n"); + semMutexShow (client->eventqLock,1); + printf( "\tBlock Semaphore\n"); + semBinaryShow (client->blockSem,1); + } +} + +/* + * casr() */ void casr (unsigned level) { - size_t bytes_reserved; - struct client *client; + size_t bytes_reserved; + struct client *client; - printf( "Channel Access Server V%d.%d\n", - CA_PROTOCOL_VERSION, - CA_MINOR_VERSION); + printf ("Channel Access Server V%d.%d\n", + CA_PROTOCOL_VERSION, CA_MINOR_VERSION); - LOCK_CLIENTQ; - client = (struct client *) ellNext(&clientQ); - if (!client) { - printf("No clients connected.\n"); - } - while (client) { + LOCK_CLIENTQ + client = (struct client *) ellNext (&clientQ); + if (!client) { + printf("No clients connected.\n"); + } + while (client) { - log_one_client(client, level); + log_one_client(client, level); - client = (struct client *) ellNext(&client->node); - } - UNLOCK_CLIENTQ; + client = (struct client *) ellNext(&client->node); + } + UNLOCK_CLIENTQ - if (level>=2 && prsrv_cast_client) { - log_one_client(prsrv_cast_client, level); - } - - if (level>=2u) { - bytes_reserved = 0u; - bytes_reserved += sizeof (struct client) * - freeListItemsAvail (rsrvClientFreeList); - bytes_reserved += sizeof (struct channel_in_use) * - freeListItemsAvail (rsrvChanFreeList); - bytes_reserved += (sizeof(struct event_ext)+db_sizeof_event_block()) * - freeListItemsAvail (rsrvEventFreeList); - printf( "There are currently %u bytes on the server's free list\n", - bytes_reserved); - printf( "%u client(s), %u channel(s), and %u event(s) (monitors)\n", - freeListItemsAvail (rsrvClientFreeList), - freeListItemsAvail (rsrvChanFreeList), - freeListItemsAvail (rsrvEventFreeList)); + if (level>=2 && prsrv_cast_client) { + log_one_client(prsrv_cast_client, level); + } + + if (level>=2u) { + bytes_reserved = 0u; + bytes_reserved += sizeof (struct client) * + freeListItemsAvail (rsrvClientFreeList); + bytes_reserved += sizeof (struct channel_in_use) * + freeListItemsAvail (rsrvChanFreeList); + bytes_reserved += sizeof(struct event_ext) * + freeListItemsAvail (rsrvEventFreeList); + printf( "There are currently %u bytes on the server's free list\n", + bytes_reserved); + printf( "%u client(s), %u channel(s), and %u event(s) (monitors)\n", + freeListItemsAvail (rsrvClientFreeList), + freeListItemsAvail (rsrvChanFreeList), + freeListItemsAvail (rsrvEventFreeList)); - if(pCaBucket){ - printf( "The server's resource id conversion table:\n"); - LOCK_CLIENTQ; - bucketShow (pCaBucket); - UNLOCK_CLIENTQ; - } + if(pCaBucket){ + printf( "The server's resource id conversion table:\n"); + LOCK_CLIENTQ; + bucketShow (pCaBucket); + UNLOCK_CLIENTQ; + } - caPrintAddrList (&beaconAddrList); - } + caPrintAddrList (&beaconAddrList); + } } - - -/* - * log_one_client() - * +/* + * destroy_client () */ -LOCAL void log_one_client(struct client *client, unsigned level) +void destroy_client (struct client *client) { - int i; - struct channel_in_use *pciu; - char *pproto; - double send_delay; - double recv_delay; - unsigned long bytes_reserved; - char *state[] = {"up", "down"}; - TS_STAMP current; - char clientHostName[256]; + struct event_ext *pevext; + struct channel_in_use *pciu; + int status; - ipAddrToA (&client->addr, clientHostName, sizeof(clientHostName)); + if (!client) { + return; + } + + if (client->proto != IPPROTO_TCP) { + errlogPrintf ("CAS: non TCP client delete ignored\n"); + return; + } - if(client->proto == IPPROTO_UDP){ - pproto = "UDP"; - } - else if(client->proto == IPPROTO_TCP){ - pproto = "TCP"; - } - else{ - pproto = "UKN"; - } + LOCK_CLIENTQ; + ellDelete (&clientQ, &client->node); + UNLOCK_CLIENTQ; + if (CASDEBUG>0) { + errlogPrintf ("CAS: Connection %d Terminated\n", client->sock); + } - tsStampGetCurrent(¤t); - send_delay = tsStampDiffInSeconds(¤t,&client->time_at_last_send); - recv_delay = tsStampDiffInSeconds(¤t,&client->time_at_last_recv); + /* + * exit flow control so the event system will + * shutdown correctly + */ + db_event_flow_ctrl_mode_off (client->evuser); - printf( "%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)); - if (level>=1) { - printf( "\tTId=0X%lX, Protocol=%3s, Socket FD=%d\n", - (unsigned long) client->tid, - pproto, - client->sock); - printf( - "\tSecs since last send %6.2f, Secs since last receive %6.2f\n", - send_delay, recv_delay); - printf( - "\tUnprocessed request bytes=%lu, Undelivered response bytes=%lu, State=%s\n", - client->send.stk, - client->recv.cnt - client->recv.stk, - state[client->disconnect?1:0]); + /* + * Server task deleted first since close() is not reentrant + */ + if ( client->tid != 0 ) { + taskwdRemove (client->tid); + } - } + while(TRUE){ + semMutexMustTake (client->addrqLock); + pciu = (struct channel_in_use *) ellGet(&client->addrq); + semMutexGive (client->addrqLock); + if (!pciu) { + break; + } - if (level>=2u) { - bytes_reserved = 0; - bytes_reserved += sizeof(struct client); - - semMutexMustTake(client->addrqLock); - pciu = (struct channel_in_use *) client->addrq.node.next; - while (pciu){ - bytes_reserved += sizeof(struct channel_in_use); - bytes_reserved += - (sizeof(struct event_ext)+db_sizeof_event_block())* - ellCount(&pciu->eventq); - if(pciu->pPutNotify){ - bytes_reserved += sizeof(*pciu->pPutNotify); - bytes_reserved += pciu->pPutNotify->valueSize; - } - pciu = (struct channel_in_use *) ellNext(&pciu->node); - } - semMutexGive(client->addrqLock); - printf( "\t%ld bytes allocated\n", bytes_reserved); - - - semMutexMustTake(client->addrqLock); - pciu = (struct channel_in_use *) client->addrq.node.next; - i=0; - while (pciu){ - printf( "\t%s(%d%c%c)", - pciu->addr.precord->name, - ellCount(&pciu->eventq), - asCheckGet(pciu->asClientPVT)?'r':'-', - rsrvCheckPut(pciu)?'w':'-'); - pciu = (struct channel_in_use *) ellNext(&pciu->node); - if( ++i % 3 == 0){ - printf("\n"); + /* + * put notify in progress needs to be deleted + */ + if (pciu->pPutNotify) { + if (pciu->pPutNotify->busy) { + dbNotifyCancel (&pciu->pPutNotify->dbPutNotify); } - } - semMutexGive(client->addrqLock); - printf("\n"); - } + } - if (level >= 3u) { - printf( "\tSend Lock\n"); - semMutexShow(client->lock,1); - printf( "\tPut Notify Lock\n"); - semMutexShow (client->putNotifyLock,1); - printf( "\tAddress Queue Lock\n"); - semMutexShow (client->addrqLock,1); - printf( "\tEvent Queue Lock\n"); - semMutexShow (client->eventqLock,1); - printf( "\tBlock Semaphore\n"); - semBinaryShow (client->blockSem,1); - } + while (TRUE){ + /* + * AS state change could be using this list + */ + semMutexMustTake (client->eventqLock); + + pevext = (struct event_ext *) ellGet(&pciu->eventq); + semMutexGive (client->eventqLock); + if(!pevext){ + break; + } + + if (pevext->pdbev) { + db_cancel_event (pevext->pdbev); + } + freeListFree (rsrvEventFreeList, pevext); + } + status = db_flush_extra_labor_event (client->evuser); + assert (status==DB_EVENT_OK); + if (pciu->pPutNotify) { + free(pciu->pPutNotify); + } + LOCK_CLIENTQ; + status = bucketRemoveItemUnsignedId ( + pCaBucket, + &pciu->sid); + UNLOCK_CLIENTQ; + if(status != S_bucket_success){ + errPrintf ( + status, + __FILE__, + __LINE__, + "Bad id=%d at close", + pciu->sid); + } + status = asRemoveClient(&pciu->asClientPVT); + if(status!=0 && status != S_asLib_asNotActive){ + printf("And the status is %x \n", status); + errPrintf(status, __FILE__, __LINE__, "asRemoveClient"); + } + + /* + * place per channel block onto the + * free list + */ + freeListFree (rsrvChanFreeList, pciu); + } + + if ( client->evuser ) { + db_close_events (client->evuser); + } + + if (client->sock!=SOCKET_ERROR) { + if ( socket_close (client->sock) < 0) { + errlogPrintf("CAS: Unable to close socket\n"); + } + } + + semMutexDestroy (client->eventqLock); + + semMutexDestroy (client->addrqLock); + + semMutexDestroy (client->putNotifyLock); + + semMutexDestroy (client->lock); + + semBinaryDestroy (client->blockSem); + + if (client->pUserName) { + free (client->pUserName); + } + + if (client->pHostName) { + free (client->pHostName); + } + + client->minor_version_number = CA_UKN_MINOR_VERSION; + + freeListFree (rsrvClientFreeList, client); } diff --git a/src/rsrv/cast_server.c b/src/rsrv/cast_server.c index 5e4a513f1..4f7ba1e84 100644 --- a/src/rsrv/cast_server.c +++ b/src/rsrv/cast_server.c @@ -1,74 +1,56 @@ /* - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 5-88 + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 * - * Experimental Physics and Industrial Control System (EPICS) + * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory * - * Modification Log: - * ----------------- - * .00 joh 030191 Fixed cast server to not block on TCP - * .01 joh 030891 now reuses old client structure - * .02 joh 032091 allways flushes if the client changes and the old - * client has a TCP connection.(bug introduced by .00) - * .03 joh 071291 changes to avoid confusion when a rebooted - * client uses the same port number - * .04 joh 080591 changed printf() to a logMsg() - * .05 joh 082091 tick stamp init in create_udp_client() - * .06 joh 112291 dont change the address until after the flush - * .07 joh 112291 fixed the comments - * .08 joh 021192 better diagnostics + * Improvements + * ------------ + * .01 + * Dont send channel found message unless there is memory, a task slot, + * and a TCP socket available. Send a diagnostic instead. + * Or ... make the timeout shorter? This is only a problem if + * they persist in trying to make a connection after getting no + * response. * - * Improvements - * ------------ - * .01 - * Dont send channel found message unless there is memory, a task slot, - * and a TCP socket available. Send a diagnostic instead. - * Or ... make the timeout shorter? This is only a problem if - * they persist in trying to make a connection after getting no - * response. - * - * Notes: - * ------ - * .01 - * Replies to broadcasts are not returned over - * an existing TCP connection to avoid a TCP - * pend which could lock up the cast server. + * Notes: + * ------ + * .01 + * Replies to broadcasts are not returned over + * an existing TCP connection to avoid a TCP + * pend which could lock up the cast server. */ -static char *sccsId = "@(#) $Id$"; #include #include #include #include - -#include #include #include "osiSock.h" #include "tsStamp.h" -#include "os_depen.h" #include "osiThread.h" #include "errlog.h" #include "ellLib.h" @@ -77,13 +59,60 @@ static char *sccsId = "@(#) $Id$"; #include "envDefs.h" #include "freeList.h" #include "server.h" -#include "osiSockResource.h" + +#define TIMEOUT 60.0 /* sec */ - -LOCAL void clean_addrq(); +/* + * clean_addrq + */ +LOCAL void clean_addrq() +{ + struct channel_in_use *pciu; + struct channel_in_use *pnextciu; + TS_STAMP current; + double delay; + double maxdelay = 0; + unsigned ndelete=0; + double timeout = TIMEOUT; + int s; + tsStampGetCurrent(¤t); + + semMutexMustTake(prsrv_cast_client->addrqLock); + pnextciu = (struct channel_in_use *) + prsrv_cast_client->addrq.node.next; + + while( (pciu = pnextciu) ) { + pnextciu = (struct channel_in_use *)pciu->node.next; + + delay = tsStampDiffInSeconds(¤t,&pciu->time_at_creation); + if (delay > timeout) { + + ellDelete(&prsrv_cast_client->addrq, &pciu->node); + LOCK_CLIENTQ; + s = bucketRemoveItemUnsignedId ( + pCaBucket, + &pciu->sid); + if(s){ + errMessage (s, "Bad id at close"); + } + UNLOCK_CLIENTQ; + freeListFree(rsrvChanFreeList, pciu); + ndelete++; + if(delay>maxdelay) maxdelay = delay; + } + } + semMutexGive(prsrv_cast_client->addrqLock); + +# ifdef DEBUG + if(ndelete){ + epicsPrintf ("CAS: %d CA channels have expired after %f sec\n", + ndelete, maxdelay); + } +# endif + +} - /* * CAST_SERVER * @@ -92,60 +121,60 @@ LOCAL void clean_addrq(); */ int cast_server(void) { - struct sockaddr_in sin; - int status; - int count=0; - struct sockaddr_in new_recv_addr; - int recv_addr_size; - unsigned short port; - int nchars; - threadId tid; + struct sockaddr_in sin; + int status; + int count=0; + struct sockaddr_in new_recv_addr; + int recv_addr_size; + unsigned short port; + int nchars; + threadId tid; - taskwdInsert(threadGetIdSelf(),NULL,NULL); + taskwdInsert(threadGetIdSelf(),NULL,NULL); - port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT); + port = caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT); - recv_addr_size = sizeof(new_recv_addr); + recv_addr_size = sizeof(new_recv_addr); - if( IOC_cast_sock!=0 && IOC_cast_sock!=ERROR ) { - if( (status = socket_close(IOC_cast_sock)) == ERROR ) { + if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) { + if( (status = socket_close(IOC_cast_sock)) < 0 ) { epicsPrintf ("CAS: Unable to close master cast socket\n"); } } - /* - * Open the socket. - * Use ARPA Internet address format and datagram socket. + /* + * Open the socket. + * Use ARPA Internet address format and datagram socket. */ - if((IOC_cast_sock = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR){ - epicsPrintf ("CAS: casts socket creation error\n"); - threadSuspend(threadGetIdSelf()); - } + if ((IOC_cast_sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + epicsPrintf ("CAS: cast socket creation error\n"); + threadSuspend (); + } - /* - * some concern that vxWorks will run out of mBuf's - * if this change is made - * - * joh 11-10-98 - */ + /* + * some concern that vxWorks will run out of mBuf's + * if this change is made + * + * joh 11-10-98 + */ #if 0 - { - /* - * - * this allows for faster connects by queuing - * additional incomming UDP search frames - * - * this allocates a 32k buffer - * (uses a power of two) - */ - int size = 1u<<15u; - status = setsockopt (IOC_cast_sock, SOL_SOCKET, - SO_RCVBUF, (char *)&size, sizeof(size)); - if (status<0) { - epicsPrintf ("CAS: unable to set cast socket size\n"); - } - } + { + /* + * + * this allows for faster connects by queuing + * additional incomming UDP search frames + * + * this allocates a 32k buffer + * (uses a power of two) + */ + int size = 1u<<15u; + status = setsockopt (IOC_cast_sock, SOL_SOCKET, + SO_RCVBUF, (char *)&size, sizeof(size)); + if (status<0) { + epicsPrintf ("CAS: unable to set cast socket size\n"); + } + } #endif /* Zero the sock_addr structure */ @@ -155,16 +184,16 @@ int cast_server(void) sin.sin_port = htons(port); /* get server's Internet address */ - if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) == ERROR){ + if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){ epicsPrintf ("CAS: cast bind error\n"); socket_close (IOC_cast_sock); - threadSuspend(threadGetIdSelf()); + threadSuspend (); } /* tell clients we are on line again */ tid = threadCreate("CAonline",threadPriorityChannelAccessClient-3, - threadGetStackSize(threadStackSmall), - (THREADFUNC)rsrv_online_notify_task,0); + threadGetStackSize(threadStackSmall), + (THREADFUNC)rsrv_online_notify_task,0); if(tid == 0) { epicsPrintf ("CAS: couldnt start up online notify task because \"%s\"\n", strerror(errno)); @@ -176,13 +205,16 @@ int cast_server(void) * possible * */ - while(TRUE){ - prsrv_cast_client = create_udp_client(IOC_cast_sock); - if(prsrv_cast_client){ + while (TRUE) { + prsrv_cast_client = create_base_client (); + if (prsrv_cast_client) { break; } - threadSleep(300.0); + threadSleep(300.0); } + + prsrv_cast_client->sock = IOC_cast_sock; + prsrv_cast_client->tid = threadGetIdSelf (); while (TRUE) { status = recvfrom ( @@ -195,12 +227,12 @@ int cast_server(void) if (status<0) { epicsPrintf ("CAS: UDP recv error (errno=%s)\n", SOCKERRSTR(SOCKERRNO)); - threadSleep(1.0); + threadSleep(1.0); } else { prsrv_cast_client->recv.cnt = (unsigned long) status; prsrv_cast_client->recv.stk = 0ul; - tsStampGetCurrent(&prsrv_cast_client->time_at_last_recv); + tsStampGetCurrent(&prsrv_cast_client->time_at_last_recv); /* * If we are talking to a new client flush to the old one @@ -209,7 +241,7 @@ int cast_server(void) */ if (prsrv_cast_client->send.stk) { status = memcmp( (void *)&prsrv_cast_client->addr, (void *)&new_recv_addr, recv_addr_size); - if(status){ + if(status){ /* * if the address is different */ @@ -221,20 +253,20 @@ int cast_server(void) prsrv_cast_client->addr = new_recv_addr; } - if(CASDEBUG>1){ - char buf[40]; + 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", + errlogPrintf ("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); + if (CASDEBUG>2) + count = ellCount (&prsrv_cast_client->addrq); status = camessage( prsrv_cast_client,&prsrv_cast_client->recv); - if(status == OK){ + if(status == RSRV_OK){ if(prsrv_cast_client->recv.cnt != prsrv_cast_client->recv.stk){ char buf[40]; @@ -253,205 +285,27 @@ int cast_server(void) epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf); } - if(CASDEBUG>2){ - if(ellCount(&prsrv_cast_client->addrq)){ - epicsPrintf ("CAS: Fnd %d name matches (%d tot)\n", + if (CASDEBUG>2) { + if ( ellCount (&prsrv_cast_client->addrq) ) { + errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n", ellCount(&prsrv_cast_client->addrq)-count, ellCount(&prsrv_cast_client->addrq)); } } } - /* - * allow messages to batch up if more are comming - */ - status = socket_ioctl(IOC_cast_sock, FIONREAD, /* sic */(int) &nchars); - if(status == ERROR){ - threadSuspend(threadGetIdSelf()); - } - - if(nchars == 0){ - cas_send_msg(prsrv_cast_client, TRUE); - clean_addrq(); - } - } -} - - -/* - * clean_addrq - * - * - */ -#define TIMEOUT 60.0 /* sec */ - -LOCAL void clean_addrq() -{ - struct channel_in_use *pciu; - struct channel_in_use *pnextciu; - TS_STAMP current; - double delay; - double maxdelay = 0; - unsigned ndelete=0; - double timeout = TIMEOUT; - int s; - - tsStampGetCurrent(¤t); - - semMutexMustTake(prsrv_cast_client->addrqLock); - pnextciu = (struct channel_in_use *) - prsrv_cast_client->addrq.node.next; - - while( (pciu = pnextciu) ) { - pnextciu = (struct channel_in_use *)pciu->node.next; - - delay = tsStampDiffInSeconds(¤t,&pciu->time_at_creation); - if (delay > timeout) { - - ellDelete(&prsrv_cast_client->addrq, &pciu->node); - LOCK_CLIENTQ; - s = bucketRemoveItemUnsignedId ( - pCaBucket, - &pciu->sid); - if(s){ - errMessage (s, "Bad id at close"); - } - UNLOCK_CLIENTQ; - freeListFree(rsrvChanFreeList, pciu); - ndelete++; - if(delay>maxdelay) maxdelay = delay; - } - } - semMutexGive(prsrv_cast_client->addrqLock); - -# ifdef DEBUG - if(ndelete){ - epicsPrintf ("CAS: %d CA channels have expired after %f sec\n", - ndelete, maxdelay); - } -# endif - -} - - -/* - * CREATE_UDP_CLIENT - * - * - */ -struct client *create_udp_client(SOCKET sock) -{ - struct client *client; - - client = freeListMalloc(rsrvClientFreeList); - if(!client){ - epicsPrintf ("CAS: no space in pool for a new client\n"); - return NULL; - } - - if(CASDEBUG>2) - epicsPrintf ("CAS: Creating new udp client\n"); - - /* - * The following inits to zero done instead of a bfill since the send - * and recv buffers are large and don't need initialization. - * - * memset(client, 0, sizeof(*client)); - */ - - client->blockSem = semBinaryCreate(semEmpty); - if(!client->blockSem){ - freeListFree(rsrvClientFreeList, client); - return NULL; - } - - /* - * user name initially unknown - */ - client->pUserName = malloc(1); - if(!client->pUserName){ - semBinaryDestroy(client->blockSem); - freeListFree(rsrvClientFreeList, client); - return NULL; - } - client->pUserName[0] = '\0'; - - /* - * host name initially unknown - */ - client->pHostName = malloc(1); - if(!client->pHostName){ - semBinaryDestroy(client->blockSem); - free(client->pUserName); - freeListFree(rsrvClientFreeList, client); - return NULL; - } - client->pHostName[0] = '\0'; - - ellInit(&client->addrq); - ellInit(&client->putNotifyQue); - memset((char *)&client->addr, 0, sizeof(client->addr)); - client->tid = threadGetIdSelf(); - client->send.stk = 0ul; - client->send.cnt = 0ul; - client->recv.stk = 0ul; - client->recv.cnt = 0ul; - client->evuser = NULL; - client->disconnect = FALSE; /* for TCP only */ - tsStampGetCurrent(&client->time_at_last_send); - tsStampGetCurrent(&client->time_at_last_recv); - client->proto = IPPROTO_UDP; - client->sock = sock; - client->minor_version_number = CA_UKN_MINOR_VERSION; - - client->send.maxstk = MAX_UDP; - - client->lock = semMutexMustCreate(); - client->putNotifyLock = semMutexMustCreate(); - client->addrqLock = semMutexMustCreate(); - client->eventqLock = semMutexMustCreate(); - - client->recv.maxstk = ETHERNET_MAX_UDP; - return client; -} - - - -/* - * UDP_TO_TCP - * - * send lock must be applied - * - */ -int udp_to_tcp( -struct client *client, -SOCKET sock -) -{ - int status; - int addrSize; - - if(CASDEBUG>2){ - epicsPrintf ("CAS: converting udp client to tcp\n"); - } - - client->proto = IPPROTO_TCP; - client->send.maxstk = MAX_TCP; - client->recv.maxstk = MAX_TCP; - client->sock = sock; - client->tid = threadGetIdSelf(); - - addrSize = sizeof(client->addr); - status = getpeername( - sock, - (struct sockaddr *)&client->addr, - &addrSize); - if(status == ERROR){ - epicsPrintf ("CAS: peer address fetch failed\n"); - return ERROR; + /* + * allow messages to batch up if more are comming + */ + status = socket_ioctl(IOC_cast_sock, FIONREAD, &nchars); + if (status<0) { + errlogPrintf ("CA cast server: Unable to fetch N characters pending\n"); + cas_send_msg (prsrv_cast_client, TRUE); + clean_addrq (); } - - return OK; -} - - + else if (nchars == 0) { + cas_send_msg (prsrv_cast_client, TRUE); + clean_addrq (); + } + } +} \ No newline at end of file diff --git a/src/rsrv/online_notify.c b/src/rsrv/online_notify.c index ebf997ed2..22fc493b6 100644 --- a/src/rsrv/online_notify.c +++ b/src/rsrv/online_notify.c @@ -1,74 +1,65 @@ /* - * O N L I N E _ N O T I F Y . C + * $Id$ * - * tell CA clients this a server has joined the network + * tell CA clients this a server has joined the network * - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 103090 + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 103090 * - * Experimental Physics and Industrial Control System (EPICS) + * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory * - * History - * .00 joh 021192 better diagnostics */ -static char *sccsId = "@(#) $Id$"; - #include #include #include #include - #include -#define MAX_BLOCK_THRESHOLD 100000 - /* - * EPICS includes + * EPICS includes */ #include "osiSock.h" #include "osiThread.h" +#include "osiPoolStatus.h" #include "tsStamp.h" #include "errlog.h" #include "envDefs.h" #include "server.h" /* - * RSRV_ONLINE_NOTIFY_TASK + * RSRV_ONLINE_NOTIFY_TASK */ - - int rsrv_online_notify_task() { caAddrNode *pNode; - double delay; - double maxdelay; + double delay; + double maxdelay; long longStatus; double maxPeriod; caHdr msg; - struct sockaddr_in recv_addr; - SOCKET status; + int status; SOCKET sock; int true = TRUE; unsigned short port; @@ -76,23 +67,16 @@ int rsrv_online_notify_task() taskwdInsert(threadGetIdSelf(),NULL,NULL); longStatus = envGetDoubleConfigParam ( - &EPICS_CA_BEACON_PERIOD, - &maxPeriod); + &EPICS_CA_BEACON_PERIOD, &maxPeriod); if (longStatus || maxPeriod<=0.0) { maxPeriod = 15.0; - epicsPrintf ( - "EPICS \"%s\" float fetch failed\n", - EPICS_CA_BEACON_PERIOD.name); - epicsPrintf ( - "Setting \"%s\" = %f\n", - EPICS_CA_BEACON_PERIOD.name, - maxPeriod); + epicsPrintf ("EPICS \"%s\" float fetch failed\n", + EPICS_CA_BEACON_PERIOD.name); + epicsPrintf ("Setting \"%s\" = %f\n", + EPICS_CA_BEACON_PERIOD.name, maxPeriod); } - /* - * 1/50 second initial delay between beacons - */ - delay = .02; + delay = 0.02; /* initial beacon period in sec */ maxdelay = maxPeriod; /* @@ -100,34 +84,37 @@ int rsrv_online_notify_task() * Use ARPA Internet address format and datagram socket. * Format described in . */ - if((sock = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR){ - errlogPrintf("CAS: online socket creation error\n"); - abort(); + if( (sock = socket (AF_INET, SOCK_DGRAM, 0)) == SOCKET_ERROR){ + errlogPrintf ("CAS: online socket creation error\n"); + threadSuspend (); } - status = setsockopt( sock, - SOL_SOCKET, - SO_BROADCAST, - (char *)&true, - sizeof(true)); - if(status<0){ - abort(); + status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, + (char *)&true, sizeof(true)); + if (status<0) { + errlogPrintf ("CAS: online socket set up error\n"); + threadSuspend (); } - memset((char *)&recv_addr, 0, sizeof recv_addr); - recv_addr.sin_family = AF_INET; - recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* let slib pick lcl addr */ - recv_addr.sin_port = htons(0); /* let slib pick port */ - status = bind(sock, (struct sockaddr *)&recv_addr, sizeof recv_addr); - if(status<0) - abort(); +#if 0 + { + struct sockaddr_in recv_addr; + + memset((char *)&recv_addr, 0, sizeof recv_addr); + recv_addr.sin_family = AF_INET; + recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* let slib pick lcl addr */ + recv_addr.sin_port = htons(0); /* let slib pick port */ + status = bind(sock, (struct sockaddr *)&recv_addr, sizeof recv_addr); + if(status<0) + abort(); + } +#endif memset((char *)&msg, 0, sizeof msg); msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP); msg.m_count = htons (ca_server_port); - msg.m_available = htonl (INADDR_ANY); - ellInit(&beaconAddrList); + ellInit (&beaconAddrList); /* * load user and auto configured @@ -137,49 +124,63 @@ int rsrv_online_notify_task() caSetupBCastAddrList (&beaconAddrList, sock, port); # ifdef DEBUG - caPrintAddrList(&beaconAddrList); + caPrintAddrList (&beaconAddrList); # endif - while(TRUE){ - int maxBlock; + while (TRUE) { /* - * check max block and disable new channels - * if its to small + * check to see if we are running low on memory + * and disable new channels if so */ - maxBlock = memFindMax(); - if(maxBlockdestAddr.sa, - sizeof(pNode->destAddr.sa)); - if(status < 0){ - errlogPrintf( "%s: CA beacon error was \"%s\"\n", - (int) __FILE__, - (int) SOCKERRSTR(SOCKERRNO)); + casSufficentSpaceInPool = osiSufficentSpaceInPool (); + + pNode = (caAddrNode *) ellFirst (&beaconAddrList); + while (pNode) { + char buf[64]; + + status = connect (sock, &pNode->destAddr.sa, sizeof(pNode->destAddr.sa)); + if (status<0) { + ipAddrToA (&pNode->destAddr.in, buf, sizeof(buf)); + errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n", + __FILE__, buf, SOCKERRSTR(SOCKERRNO)); } - else{ - assert(status == sizeof(msg)); + else { + struct sockaddr_in if_addr; + + int size = sizeof (if_addr); + status = getsockname (sock, (struct sockaddr *) &if_addr, &size); + if (status<0) { + errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n", + __FILE__, SOCKERRSTR(SOCKERRNO)); + } + else if (if_addr.sin_family==AF_INET) { + msg.m_available = if_addr.sin_addr.s_addr; + +ipAddrToA (&if_addr, buf, sizeof(buf)); +printf ("**** Setting local address to \"%s\" - this may not work correctly ****\n", buf); + + status = send (sock, (char *)&msg, sizeof(msg), 0); + if (status < 0) { + ipAddrToA (&pNode->destAddr.in, buf, sizeof(buf)); + errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n", + __FILE__, buf, SOCKERRSTR(SOCKERRNO)); + } + else { + assert (status == sizeof(msg)); + } + } } - pNode = (caAddrNode *)pNode->node.next; } + threadSleep(delay); - if (delaymaxdelay) delay = maxdelay; - } + if (delaymaxdelay) { + delay = maxdelay; + } + } } } diff --git a/src/rsrv/server.h b/src/rsrv/server.h index 284cbbaa8..babde4411 100644 --- a/src/rsrv/server.h +++ b/src/rsrv/server.h @@ -1,42 +1,29 @@ /* - * Author: Jeffrey O. Hill - * hill@luke.lanl.gov - * (505) 665 1831 - * Date: 5-88 + * Author: Jeffrey O. Hill + * hill@luke.lanl.gov + * (505) 665 1831 + * Date: 5-88 * - * Experimental Physics and Industrial Control System (EPICS) + * Experimental Physics and Industrial Control System (EPICS) * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * Modification Log: - * ----------------- - * .01 joh 060691 removed 4 byte count from the beginning of - * of each message - * .02 joh 060791 moved send_msg stuff into caserverio.c - * .03 joh 071291 moved time stamp from client to the - * channel in use block - * .04 joh 071591 added ticks at last io to the client structure - * .05 joh 103191 moved lock from msg buf to client structure - * .06 joh 050692 added declaration for cac_send_heartbeat() - * .07 joh 022492 added get flag to the event ext block - * .08 joh 090893 added sid field to channel in use block + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory * */ @@ -51,8 +38,6 @@ static char *serverhSccsId = "@(#) $Id$"; # define HDRVERSIONID(NAME,VERS) #endif /*CAS_VERSION_GLOBAL*/ -#define APIENTRY - #include "epicsAssert.h" #include "ellLib.h" @@ -73,6 +58,9 @@ static char *serverhSccsId = "@(#) $Id$"; #include "asLib.h" #include "asDbLib.h" +#define RSRV_OK 0 +#define RSRV_ERROR (-1) + /* * !! buf must be the first item in this structure !! * This guarantees that buf will have 8 byte natural @@ -101,70 +89,69 @@ static char *serverhSccsId = "@(#) $Id$"; * o four unsigned longs also take up a multiple of 8 bytes * (usually 2). * NOTE: - * o we should solve the above message alignment problems by - * allocating the message buffers + * o we should solve the above message alignment problems by + * allocating the message buffers * */ -struct message_buffer{ - char buf[MAX_MSG_SIZE]; - unsigned long stk; - unsigned long maxstk; - unsigned long cnt; - unsigned long pad0; /* force 8 byte alignement */ +struct message_buffer { + char buf[MAX_MSG_SIZE]; + unsigned long stk; + unsigned long maxstk; + unsigned long cnt; + unsigned long pad0; /* force 8 byte alignement */ }; -struct client{ - ELLNODE node; - struct message_buffer send; - struct message_buffer recv; - semMutexId lock; - semMutexId putNotifyLock; - semMutexId addrqLock; - semMutexId eventqLock; - ELLLIST addrq; - ELLLIST putNotifyQue; - struct sockaddr_in addr; - - TS_STAMP time_at_last_send; - TS_STAMP time_at_last_recv; - void *evuser; - char *pUserName; - char *pHostName; - semBinaryId blockSem; /* used whenever the client blocks */ - SOCKET sock; - int proto; - threadId tid; - unsigned minor_version_number; - char disconnect; /* disconnect detected */ +struct client { + ELLNODE node; + struct message_buffer send; + struct message_buffer recv; + semMutexId lock; + semMutexId putNotifyLock; + semMutexId addrqLock; + semMutexId eventqLock; + ELLLIST addrq; + ELLLIST putNotifyQue; + struct sockaddr_in addr; + TS_STAMP time_at_last_send; + TS_STAMP time_at_last_recv; + void *evuser; + char *pUserName; + char *pHostName; + semBinaryId blockSem; /* used whenever the client blocks */ + SOCKET sock; + int proto; + threadId tid; + unsigned minor_version_number; + char disconnect; /* disconnect detected */ }; /* * for tracking db put notifies */ -typedef struct rsrv_put_notify{ - ELLNODE node; - PUTNOTIFY dbPutNotify; - caHdr msg; - unsigned long valueSize; /* size of block pointed to by dbPutNotify */ - int busy; /* put notify in progress */ -}RSRVPUTNOTIFY; +typedef struct rsrv_put_notify { + ELLNODE node; + PUTNOTIFY dbPutNotify; + caHdr msg; + unsigned long valueSize; /* size of block pointed to by dbPutNotify */ + int busy; /* put notify in progress */ +} RSRVPUTNOTIFY; /* * per channel structure * (stored in addrq off of a client block) */ -struct channel_in_use{ - ELLNODE node; - ELLLIST eventq; - struct client *client; - RSRVPUTNOTIFY *pPutNotify; /* potential active put notify */ - const unsigned cid; /* client id */ - const unsigned sid; /* server id */ - TS_STAMP time_at_creation; /* for UDP timeout */ - struct dbAddr addr; - ASCLIENTPVT asClientPVT; +struct channel_in_use { + ELLNODE node; + ELLLIST eventq; + struct client *client; + RSRVPUTNOTIFY *pPutNotify; /* potential active put notify */ + const unsigned cid; /* client id */ + const unsigned sid; /* server id */ + TS_STAMP time_at_creation; /* for UDP timeout */ + struct dbAddr addr; + ASCLIENTPVT asClientPVT; }; @@ -172,70 +159,55 @@ struct channel_in_use{ * Event block extension for channel access * some things duplicated for speed */ -struct event_ext{ -ELLNODE node; -caHdr msg; -struct channel_in_use *pciu; -struct event_block *pdbev; /* ptr to db event block */ -unsigned size; /* for speed */ -unsigned mask; -char modified; /* mod & ev flw ctrl enbl */ -char send_lock; /* lock send buffer */ +struct event_ext { + ELLNODE node; + caHdr msg; + struct channel_in_use *pciu; + struct event_block *pdbev; /* ptr to db event block */ + 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 */ -#ifdef GLBLSOURCE -# define GLBLTYPE -# define GLBLTYPE_INIT(A) +/* NOTE: external used so they remember the state across loads */ +#ifdef GLBLSOURCE +# define GLBLTYPE +# define GLBLTYPE_INIT(A) #else -# define GLBLTYPE extern -# define GLBLTYPE_INIT(A) +# define GLBLTYPE extern +# define GLBLTYPE_INIT(A) #endif - /* - * for debug-level dependent messages: + * for debug-level dependent messages: */ #ifdef DEBUG - -# define DLOG(level, fmt, a1, a2, a3, a4, a5, a6) \ - if (CASDEBUG > level) \ - errlogPrintf (fmt, a1, a2, a3, a4, a5, a6) - -# define DBLOCK(level, code) \ - if (CASDEBUG > level) \ - { \ - code; \ - } - +# define DLOG(level, fmt, a1, a2, a3, a4, a5, a6) \ + if (CASDEBUG > level) errlogPrintf (fmt, a1, a2, a3, a4, a5, a6) +# define DBLOCK(level, code) \ + if (CASDEBUG > level) { code; } #else - -# define DLOG(level, fmt, a1, a2, a3, a4, a5, a6) -# define DBLOCK(level, code) - +# define DLOG(level, fmt, a1, a2, a3, a4, a5, a6) +# define DBLOCK(level, code) #endif -GLBLTYPE int CASDEBUG; -GLBLTYPE SOCKET IOC_sock; -GLBLTYPE SOCKET IOC_cast_sock; -GLBLTYPE unsigned short ca_server_port; -GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */ -GLBLTYPE ELLLIST beaconAddrList; -GLBLTYPE semMutexId clientQlock; -GLBLTYPE struct client *prsrv_cast_client; -GLBLTYPE BUCKET *pCaBucket; -GLBLTYPE void *rsrvClientFreeList; -GLBLTYPE void *rsrvChanFreeList; -GLBLTYPE void *rsrvEventFreeList; +GLBLTYPE int CASDEBUG; +GLBLTYPE SOCKET IOC_sock; +GLBLTYPE SOCKET IOC_cast_sock; +GLBLTYPE unsigned short ca_server_port; +GLBLTYPE ELLLIST clientQ; /* locked by clientQlock */ +GLBLTYPE ELLLIST beaconAddrList; +GLBLTYPE semMutexId clientQlock; +GLBLTYPE struct client *prsrv_cast_client; +GLBLTYPE BUCKET *pCaBucket; +GLBLTYPE void *rsrvClientFreeList; +GLBLTYPE void *rsrvChanFreeList; +GLBLTYPE void *rsrvEventFreeList; #define CAS_HASH_TABLE_SIZE 4096 -/* - * set true if max memory block drops below MAX_BLOCK_THRESHOLD - */ -#define MAX_BLOCK_THRESHOLD 100000 -GLBLTYPE int casBelowMaxBlockThresh; +GLBLTYPE int casSufficentSpaceInPool; #define SEND_LOCK(CLIENT) semMutexMustTake((CLIENT)->lock) #define SEND_UNLOCK(CLIENT) semMutexGive((CLIENT)->lock) @@ -244,48 +216,36 @@ GLBLTYPE int casBelowMaxBlockThresh; ((caHdr *) &(CLIENT)->send.buf[(CLIENT)->send.stk]) /* - * ALLOC_MSG get a ptr to space in the buffer - * END_MSG push a message onto the buffer stack + * ALLOC_MSG get a ptr to space in the buffer + * END_MSG push a message onto the buffer stack * */ -#define ALLOC_MSG(CLIENT, EXTSIZE) cas_alloc_msg(CLIENT, EXTSIZE) +#define ALLOC_MSG(CLIENT, EXTSIZE) cas_alloc_msg (CLIENT, EXTSIZE) #define END_MSG(CLIENT)\ EXTMSGPTR(CLIENT)->m_postsize = CA_MESSAGE_ALIGN(EXTMSGPTR(CLIENT)->m_postsize),\ (CLIENT)->send.stk += sizeof(caHdr) + EXTMSGPTR(CLIENT)->m_postsize +#define LOCK_CLIENTQ semMutexMustTake (clientQlock); +#define UNLOCK_CLIENTQ semMutexGive (clientQlock); -#define LOCK_CLIENTQ semMutexMustTake(clientQlock) -#define UNLOCK_CLIENTQ semMutexGive(clientQlock) - -struct client *existing_client(); -int camsgtask(); -void cas_send_msg(); -caHdr *cas_alloc_msg(); -int rsrv_online_notify_task(); -void cac_send_heartbeat(); - -int client_stat(unsigned level); -void casr(unsigned level); -int req_server(void); -int cast_server(void); -int free_client(struct client *client); -struct client *create_udp_client(SOCKET sock); -int udp_to_tcp(struct client *client, SOCKET sock); - -int camessage( -struct client *client, -struct message_buffer *recv -); - -void cas_send_heartbeat( -struct client *pc -); - -void write_notify_reply(void *pArg); +int client_stat (unsigned level); +void casr (unsigned level); +void camsgtask (struct client *client); +void cas_send_msg (struct client *pclient, int lock_needed); +caHdr *cas_alloc_msg (struct client *pclient, unsigned extsize); +int rsrv_online_notify_task (void); +void cac_send_heartbeat (void); +int cast_server (void); +struct client *create_base_client (); +int camessage (struct client *client, + struct message_buffer *recv); +void cas_send_heartbeat (struct client *pc); +void write_notify_reply (void *pArg); int rsrvCheckPut (const struct channel_in_use *pciu); - +struct client *create_client (SOCKET sock); +void destroy_client (struct client *client); /* * !!KLUDGE!! @@ -294,7 +254,7 @@ int rsrvCheckPut (const struct channel_in_use *pciu); * to include both dbAccess.h and db_access.h at the * same time. */ -#define S_db_Blocked (M_dbAccess|39) /*Request is Blocked*/ +#define S_db_Blocked (M_dbAccess|39) /*Request is Blocked*/ #define S_db_Pending (M_dbAccess|37) /*Request is pending*/ #endif /*INCLserverh*/