diff --git a/src/ca/Makefile.Unix b/src/ca/Makefile.Unix index e60913b7b..563f16654 100644 --- a/src/ca/Makefile.Unix +++ b/src/ca/Makefile.Unix @@ -25,7 +25,7 @@ LIBOBJS = \ LIBNAME = libca.a -PROD = caRepeater acctst +PROD = caRepeater include $(EPICS)/config/RULES.Unix diff --git a/src/ca/Makefile.Vx b/src/ca/Makefile.Vx index c097a8825..11ec90556 100644 --- a/src/ca/Makefile.Vx +++ b/src/ca/Makefile.Vx @@ -11,10 +11,9 @@ SRCS.c = \ OBJS = \ iocinf.o access.o test_event.o service.o flow_control.o \ - repeater.o conn.o syncgrp.o if_depen.o bsd_depen.o vxWorks_depen.o \ - acctst.o + repeater.o conn.o syncgrp.o if_depen.o bsd_depen.o vxWorks_depen.o -PROD = caLib acctst.o +PROD = caLib include $(EPICS)/config/RULES.Vx diff --git a/src/ca/access.c b/src/ca/access.c index 55d8ba3d2..882755ab9 100644 --- a/src/ca/access.c +++ b/src/ca/access.c @@ -481,7 +481,8 @@ int APIENTRY ca_task_initialize(void) */ int ca_os_independent_init (void) { - unsigned sec; + unsigned sec; + long status; ca_static->ca_exception_func = ca_default_exception_handler; ca_static->ca_exception_arg = NULL; @@ -531,6 +532,27 @@ int ca_os_independent_init (void) bucketCreate(CLIENT_HASH_TBL_SIZE); assert(ca_static->ca_pFastBucket); + status = envGetDoubleConfigParam ( + &EPICS_CA_CONN_TMO, + &ca_static->ca_connectTMO); + if (status) { + ca_static->ca_connectTMO = + CA_CONN_VERIFY_PERIOD; + ca_printf ( + "EPICS \"%s\" float fetch failed\n", + EPICS_CA_CONN_TMO.name); + ca_printf ( + "Setting \"%s\" = %f\n", + EPICS_CA_CONN_TMO.name, + ca_static->ca_connectTMO); + } + + ca_static->ca_repeater_port = + caFetchPortConfig(&EPICS_CA_REPEATER_PORT, CA_REPEATER_PORT); + + ca_static->ca_server_port = + caFetchPortConfig(&EPICS_CA_SERVER_PORT, CA_SERVER_PORT); + if (repeater_installed()==FALSE) { ca_spawn_repeater(); } @@ -2539,7 +2561,7 @@ void clearChannelResources(unsigned id) ca_static->ca_pSlowBucket, &chix->cid); assert (status == BUCKET_SUCCESS); free (chix); - if (!piiu->chidlist.count){ + if (piiu!=piiuCast && !piiu->chidlist.count){ TAG_CONN_DOWN(piiu); } @@ -2911,20 +2933,30 @@ void ca_ready_message(struct ioc_in_use *piiu) * echo_request (lock must be on) * */ -void echo_request(struct ioc_in_use *piiu) +int echo_request(struct ioc_in_use *piiu, ca_time *pCurrentTime) { - struct extmsg hdr; + int status; + struct extmsg *phdr; - hdr.m_cmmd = htons(IOC_ECHO); - hdr.m_type = htons(0); - hdr.m_count = htons(0); - hdr.m_cid = htons(0); - hdr.m_available = htons(0); - hdr.m_postsize = 0; + status = cac_alloc_msg_no_flush (piiu, sizeof(*phdr), &phdr); + if (status) { + return status; + } + + phdr->m_cmmd = htons(IOC_ECHO); + phdr->m_type = htons(0); + phdr->m_count = htons(0); + phdr->m_cid = htons(0); + phdr->m_available = htons(0); + phdr->m_postsize = 0; + + CAC_ADD_MSG(piiu); - cac_push_msg(piiu, &hdr, NULL); - + piiu->echoPending = TRUE; piiu->send_needed = TRUE; + piiu->timeAtEchoRequest = *pCurrentTime; + + return ECA_NORMAL; } diff --git a/src/ca/conn.c b/src/ca/conn.c index d10f44abe..e7dde9439 100644 --- a/src/ca/conn.c +++ b/src/ca/conn.c @@ -90,7 +90,7 @@ void manage_conn(int silent) piiu; piiu = (IIU *) piiu->node.next){ - if(piiu == piiuCast || !piiu->conn_up){ + if (piiu == piiuCast || !piiu->conn_up) { continue; } @@ -98,11 +98,11 @@ void manage_conn(int silent) * mark connection for shutdown if outgoing messages * are not accepted by TCP/IP for several seconds */ - if(piiu->sendPending){ + if (piiu->sendPending) { delay = cac_time_diff ( ¤t, &piiu->timeAtSendBlock); - if(delay > CA_CONN_VERIFY_PERIOD){ + if (delay>ca_static->ca_connectTMO) { TAG_CONN_DOWN(piiu); continue; } @@ -143,18 +143,11 @@ void manage_conn(int silent) } } else{ - int sendBytesAvailable; - - sendBytesAvailable = - cacRingBufferWriteSize(&piiu->send, TRUE); delay = cac_time_diff ( ¤t, &piiu->timeAtLastRecv); - if(delay>CA_CONN_VERIFY_PERIOD && - sendBytesAvailable>sizeof(struct extmsg)){ - piiu->echoPending = TRUE; - piiu->timeAtEchoRequest = current; - echo_request(piiu); + if (delay>ca_static->ca_connectTMO) { + echo_request(piiu, ¤t); } } @@ -594,29 +587,29 @@ bhe *lookupBeaconInetAddr(struct in_addr *pnet_addr) * * LOCK must be applied */ -void removeBeaconInetAddr(struct in_addr *pnet_addr) +void removeBeaconInetAddr (struct in_addr *pnet_addr) { bhe *pBHE; bhe **ppBHE; unsigned index; - index = ntohl(pnet_addr->s_addr); + index = ntohl (pnet_addr->s_addr); index &= BHT_INET_ADDR_MASK; - assert(indexca_beaconHash)); + assert (indexca_beaconHash)); ppBHE = &ca_static->ca_beaconHash[index]; pBHE = *ppBHE; - while(pBHE){ - if(pBHE->inetAddr.s_addr == pnet_addr->s_addr){ + while (pBHE) { + if (pBHE->inetAddr.s_addr == pnet_addr->s_addr) { *ppBHE = pBHE->pNext; - free(pBHE); + free (pBHE); return; } ppBHE = &pBHE->pNext; pBHE = *ppBHE; } - assert(0); + assert (0); } diff --git a/src/ca/iocinf.c b/src/ca/iocinf.c index 0c62a4184..fca280e73 100644 --- a/src/ca/iocinf.c +++ b/src/ca/iocinf.c @@ -190,7 +190,8 @@ int net_proto } pNode->destAddr.inetAddr.sin_family = AF_INET; pNode->destAddr.inetAddr.sin_addr = *pnet_addr; - pNode->destAddr.inetAddr.sin_port = htons(CA_SERVER_PORT); + pNode->destAddr.inetAddr.sin_port = + htons (ca_static->ca_server_port); ellAdd(&piiu->destAddr, &pNode->node); piiu->recvBytes = tcp_recv_msg; piiu->sendBytes = cac_tcp_send_msg_piiu; @@ -426,21 +427,13 @@ int net_proto } /* - * LOCK is for piiu->destAddr list - * (lock outside because this is used by the server also) + * load user and auto configured + * broadcast address list */ - LOCK; - caDiscoverInterfaces( - &piiu->destAddr, - sock, - CA_SERVER_PORT); - UNLOCK; - - caAddConfiguredAddr( + caSetupBCastAddrList( &piiu->destAddr, - &EPICS_CA_ADDR_LIST, - sock, - CA_SERVER_PORT); + sock, + ca_static->ca_server_port); cacRingBufferInit(&piiu->recv, sizeof(piiu->send.buf)); cacRingBufferInit(&piiu->send, min(MAX_UDP, @@ -482,6 +475,58 @@ int net_proto return ECA_NORMAL; } + +/* + * caSetupBCastAddrList() + */ +void caSetupBCastAddrList (ELLLIST *pList, SOCKET sock, unsigned port) +{ + char *pstr; + ENV_PARAM yesno; + int yes; + + /* + * dont load the list twice + */ + assert (ellCount(pList)==0); + + /* + * Check to see if the user has disabled + * initializing the search b-cast list + * from the interfaces found. + */ + yes = TRUE; + pstr = envGetConfigParam ( + &EPICS_CA_AUTO_ADDR_LIST, + sizeof(yesno.dflt), + yesno.dflt); + if (pstr) { + if (strstr(pstr,"no")||strstr(pstr,"NO")) { + yes = FALSE; + } + } + + /* + * LOCK is for piiu->destAddr list + * (lock outside because this is used by the server also) + */ + if (yes) { + caDiscoverInterfaces( + pList, + sock, + port); + } + + caAddConfiguredAddr( + pList, + &EPICS_CA_ADDR_LIST, + sock, + port); + + if (ellCount(pList)==0) { + ca_signal (ECA_NOSEARCHADDR, NULL); + } +} /* @@ -529,7 +574,7 @@ void notify_ca_repeater() memset((char *)&msg, 0, sizeof(msg)); msg.m_cmmd = htons(REPEATER_REGISTER); msg.m_available = saddr.sin_addr.s_addr; - saddr.sin_port = htons(CA_CLIENT_PORT); + saddr.sin_port = htons(ca_static->ca_repeater_port); /* * Intentionally sending a zero length message here * until most CA repeater daemons have been restarted @@ -1097,116 +1142,116 @@ void close_ioc (struct ioc_in_use *piiu) /* * dont close twice */ - if(piiu->sock_chan == INVALID_SOCKET){ - return; - } + assert (piiu->sock_chan!=INVALID_SOCKET); LOCK; - ellDelete(&iiuList, &piiu->node); + ellDelete (&iiuList, &piiu->node); /* * attempt to clear out messages in recv queue */ - (*piiu->procInput)(piiu); + (*piiu->procInput) (piiu); - if(piiu == piiuCast){ + + if (piiu == piiuCast) { piiuCast = NULL; } - - /* - * Mark all of their channels disconnected - * prior to calling handlers incase the - * handler tries to use a channel before - * I mark it disconnected. - */ - chix = (chid) &piiu->chidlist.node.next; - while(chix = (chid) chix->node.next){ - chix->type = TYPENOTCONN; - chix->count = 0; - chix->state = cs_prev_conn; - chix->id.sid = ~0L; - chix->ar.read_access = FALSE; - chix->ar.write_access = FALSE; + else { /* - * try to reconnect + * remove IOC from the hash table */ - chix->retry = 0; - } + pNode = (caAddrNode *) piiu->destAddr.node.next; + assert (pNode); + removeBeaconInetAddr (&pNode->destAddr.inetAddr.sin_addr); + + /* + * Mark all of their channels disconnected + * prior to calling handlers incase the + * handler tries to use a channel before + * I mark it disconnected. + */ + chix = (chid) &piiu->chidlist.node.next; + while (chix = (chid) chix->node.next) { + chix->type = TYPENOTCONN; + chix->count = 0; + chix->state = cs_prev_conn; + chix->id.sid = ~0L; + chix->ar.read_access = FALSE; + chix->ar.write_access = FALSE; + /* + * try to reconnect + */ + chix->retry = 0; + } + + if (piiu->chidlist.count) { + ca_signal (ECA_DISCONN,piiu->host_name_str); + } + + /* + * call their connection handler as required + */ + chix = (chid) &piiu->chidlist.node.next; + while (chix = (chid) chix->node.next) { + LOCKEVENTS; + if (chix->pConnFunc) { + struct connection_handler_args args; + + args.chid = chix; + args.op = CA_OP_CONN_DOWN; + (*chix->pConnFunc) (args); + } + if (chix->pAccessRightsFunc) { + struct access_rights_handler_args args; + + args.chid = chix; + args.ar = chix->ar; + (*chix->pAccessRightsFunc) (args); + } + UNLOCKEVENTS; + chix->piiu = piiuCast; + } + + /* + * move all channels to the broadcast IIU + * + * if we loose the broadcast IIU its a severe error + */ + assert (piiuCast); + ellConcat (&piiuCast->chidlist, &piiu->chidlist); + assert (piiu->chidlist.count==0); + } /* * Try to reconnect */ ca_static->ca_search_retry = 0; - if(piiu->chidlist.count){ - ca_signal(ECA_DISCONN,piiu->host_name_str); - } - - /* - * remove IOC from the hash table - */ - pNode = (caAddrNode *) piiu->destAddr.node.next; - assert(pNode); - removeBeaconInetAddr(&pNode->destAddr.inetAddr.sin_addr); - - /* - * call their connection handler as required - */ - chix = (chid) &piiu->chidlist.node.next; - while(chix = (chid) chix->node.next){ + if (fd_register_func) { LOCKEVENTS; - if(chix->pConnFunc){ - struct connection_handler_args args; - - args.chid = chix; - args.op = CA_OP_CONN_DOWN; - (*chix->pConnFunc)(args); - } - if(chix->pAccessRightsFunc){ - struct access_rights_handler_args args; - - args.chid = chix; - args.ar = chix->ar; - (*chix->pAccessRightsFunc)(args); - } - UNLOCKEVENTS; - chix->piiu = piiuCast; - } - - /* - * move all channels to the broadcast IIU - * - * if we loose the broadcast IIU its a severe error - */ - assert(piiuCast); - ellConcat(&piiuCast->chidlist, &piiu->chidlist); - - assert(piiu->chidlist.count==0); - - if(fd_register_func){ - LOCKEVENTS; - (*fd_register_func)(fd_register_arg, piiu->sock_chan, FALSE); + (*fd_register_func) (fd_register_arg, piiu->sock_chan, FALSE); UNLOCKEVENTS; } - status = socket_close(piiu->sock_chan); - assert(status == 0); + status = socket_close (piiu->sock_chan); + assert (status == 0); /* * free message body cache */ - if(piiu->pCurData){ - free(piiu->pCurData); + if (piiu->pCurData) { + free (piiu->pCurData); piiu->pCurData = NULL; piiu->curDataMax = 0; } piiu->sock_chan = INVALID_SOCKET; - ellFree(&piiu->destAddr); + ellFree (&piiu->destAddr); + + free (piiu); - free(piiu); UNLOCK; } @@ -1258,7 +1303,7 @@ int repeater_installed() memset((char *)&bd,0,sizeof bd); bd.sin_family = AF_INET; bd.sin_addr.s_addr = INADDR_ANY; - bd.sin_port = htons(CA_CLIENT_PORT); + bd.sin_port = htons(ca_static->ca_repeater_port); status = bind( sock, (struct sockaddr *) &bd, sizeof bd); @@ -1605,3 +1650,36 @@ void caPrintAddrList(ELLLIST *pList) } } + +/* + * caFetchPortConfig() + */ +unsigned caFetchPortConfig(ENV_PARAM *pEnv, unsigned defaultPort) +{ + long longStatus; + long port; + + longStatus = envGetLongConfigParam(pEnv, &port); + if (longStatus!=0) { + port = defaultPort; + ca_printf ("EPICS \"%s\" integer fetch failed\n", pEnv->name); + ca_printf ("setting \"%s\" = %ld\n", pEnv->name, port); + } + + /* + * Thus must be a server port that will fit in a signed + * short + */ + if (port <= IPPORT_USERRESERVED || port>SHRT_MAX) { + ca_printf ("EPICS \"%s\" out of range\n", pEnv->name); + /* + * Quit if the port is wrong due CA coding error + */ + assert (port != defaultPort); + port = defaultPort; + ca_printf ("Setting \"%s\" = %ld\n", pEnv->name, port); + } + + return port; +} + diff --git a/src/ca/iocinf.h b/src/ca/iocinf.h index 626ba9902..d2ffc699e 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -84,6 +84,7 @@ HDRVERSIONID(iocinfh, "$Id$") #include #include #include +#include /* @@ -198,9 +199,12 @@ extern const ca_time CA_CURRENT_TIME; * long we will wait for an echo reply before we * give up and flag the connection for disconnect * - CA_ECHO_TIMEOUT. + * + * CA_CONN_VERIFY_PERIOD is normally obtained from an + * EPICS environment variable. */ -#define CA_ECHO_TIMEOUT 5 /* (sec) disconn if no echo reply tmo */ -#define CA_CONN_VERIFY_PERIOD 30 /* (sec) how often to request echo */ +#define CA_ECHO_TIMEOUT 5.0 /* (sec) disconn no echo reply tmo */ +#define CA_CONN_VERIFY_PERIOD 30.0 /* (sec) how often to request echo */ /* * only used when communicating with old servers @@ -208,7 +212,7 @@ extern const ca_time CA_CURRENT_TIME; #define CA_RETRY_PERIOD 5 /* int sec to next keepalive */ #define N_REPEATER_TRIES_PRIOR_TO_MSG 50 -#define REPEATER_TRY_PERIOD (0.1) +#define REPEATER_TRY_PERIOD (0.1) #ifdef vxWorks typedef struct caclient_put_notify{ @@ -396,6 +400,7 @@ struct ca_static{ ca_time ca_conn_next_retry; ca_time ca_conn_retry_delay; ca_time ca_last_repeater_try; + ca_real ca_connectTMO; long ca_pndrecvcnt; unsigned long ca_nextSlowBucketId; unsigned long ca_nextFastBucketId; @@ -416,6 +421,8 @@ struct ca_static{ bhe *ca_beaconHash[BHT_INET_ADDR_MASK+1]; unsigned ca_repeater_tries; unsigned ca_search_retry; /* search retry seq number */ + unsigned short ca_server_port; + unsigned short ca_repeater_port; char ca_sprintf_buf[256]; unsigned ca_post_msg_active:1; unsigned ca_manage_conn_active:1; @@ -494,7 +501,7 @@ int ca_request_event(evid monix); void ca_busy_message(struct ioc_in_use *piiu); void ca_ready_message(struct ioc_in_use *piiu); void noop_msg(struct ioc_in_use *piiu); -void echo_request(struct ioc_in_use *piiu); +int echo_request(struct ioc_in_use *piiu, ca_time *pCurrentTime); void issue_claim_channel(struct ioc_in_use *piiu, chid pchan); void issue_identify_client(struct ioc_in_use *piiu); void issue_client_host_name(struct ioc_in_use *piiu); @@ -555,6 +562,8 @@ int net_proto int ca_check_for_fp(void); +void caSetupBCastAddrList (ELLLIST *pList, SOCKET sock, unsigned port); + int ca_os_independent_init (void); void freeBeaconHash(struct ca_static *ca_temp); diff --git a/src/ca/iocmsg.h b/src/ca/iocmsg.h index a44697158..37802930c 100644 --- a/src/ca/iocmsg.h +++ b/src/ca/iocmsg.h @@ -50,9 +50,15 @@ HDRVERSIONID(iocmsgh, "@(#) $Id$ CA version 4.4") #define CA_V44(MAJOR,MINOR) ( 0 ) #endif +/* + * NOTE: These port numbers are only used if the CA repeater and + * CA server port numbers cant be obtained from the EPICS + * environment variables "EPICS_CA_REPEATER_PORT" and + * "EPICS_CA_SERVER_PORT" + */ #define CA_PORT_BASE IPPORT_USERRESERVED + 56 #define CA_SERVER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2) -#define CA_CLIENT_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2+1) +#define CA_REPEATER_PORT (CA_PORT_BASE+CA_PROTOCOL_VERSION*2+1) #define MAX_UDP 1024 #define MAX_TCP (MAX_UDP*16) /* so waveforms fit */ diff --git a/src/ca/repeater.c b/src/ca/repeater.c index 8fdd78322..75aa2b9fc 100644 --- a/src/ca/repeater.c +++ b/src/ca/repeater.c @@ -100,6 +100,11 @@ void ca_repeater() int from_size = sizeof from; struct one_client *pclient; struct one_client *pnxtclient; + short port; + + port = caFetchPortConfig( + &EPICS_CA_REPEATER_PORT, + CA_REPEATER_PORT); ellInit(&client_list); @@ -113,7 +118,7 @@ void ca_repeater() memset((char *)&bd, 0, sizeof(bd)); bd.sin_family = AF_INET; bd.sin_addr.s_addr = INADDR_ANY; - bd.sin_port = htons(CA_CLIENT_PORT); + bd.sin_port = htons(port); status = bind(sock, (struct sockaddr *)&bd, sizeof(bd)); if(status<0){ if(MYERRNO != EADDRINUSE){ diff --git a/src/ca/vxWorks_depen.c b/src/ca/vxWorks_depen.c index 3580abddf..cc823c514 100644 --- a/src/ca/vxWorks_depen.c +++ b/src/ca/vxWorks_depen.c @@ -419,7 +419,7 @@ LOCAL int cac_os_depen_exit_tid (struct ca_static *pcas, int tid) /* * stop the socket recv task - * (only after we get the LOCK here) + * !! only after we get the LOCK here !! */ if (taskIdVerify (pcas->recv_tid)==OK) { taskwdRemove (pcas->recv_tid); @@ -439,7 +439,11 @@ LOCAL int cac_os_depen_exit_tid (struct ca_static *pcas, int tid) /* * Cancel all local events * (and put call backs) + * + * !! temp release lock so that the event task + * can finish !! */ + UNLOCK; chix = (chid) & pcas->ca_local_chidlist.node; while (chix = (chid) chix->node.next) { while (monix = (evid) ellGet(&chix->eventq)) { @@ -457,7 +461,7 @@ LOCAL int cac_os_depen_exit_tid (struct ca_static *pcas, int tid) free (ppn); } } - + LOCK; /* * set ca_static for access.c