/* * ca_repeater () */ void ca_repeater () { tsFreeList < repeaterClient, 0x20 > freeList; int size; SOCKET sock; osiSockAddr from; unsigned short port; char * pBuf; pBuf = new char [MAX_UDP_RECV]; { bool success = osiSockAttach(); assert ( success ); } port = envGetInetPortConfigParam ( & EPICS_CA_REPEATER_PORT, static_cast <unsigned short> (CA_REPEATER_PORT) ); if ( ! makeSocket ( port, true, & sock ) ) { /* * test for server was already started */ if ( SOCKERRNO == SOCK_EADDRINUSE ) { osiSockRelease (); debugPrintf ( ( "CA Repeater: exiting because a repeater is already running\n" ) ); return; } char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf ( stderr, "%s: Unable to create repeater socket because \"%s\" - fatal\n", __FILE__, sockErrBuf ); osiSockRelease (); delete [] pBuf; return; } debugPrintf ( ( "CA Repeater: Attached and initialized\n" ) ); while ( true ) { osiSocklen_t from_size = sizeof ( from ); size = recvfrom ( sock, pBuf, MAX_UDP_RECV, 0, &from.sa, &from_size ); if ( size < 0 ) { int errnoCpy = SOCKERRNO; // Avoid spurious ECONNREFUSED bug in linux if ( errnoCpy == SOCK_ECONNREFUSED ) { continue; } // Avoid ECONNRESET from connected socket in windows if ( errnoCpy == SOCK_ECONNRESET ) { continue; } char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf ( stderr, "CA Repeater: unexpected UDP recv err: %s\n", sockErrBuf ); continue; } caHdr * pMsg = ( caHdr * ) pBuf; /* * both zero length message and a registration message * will register a new client */ if ( ( (size_t) size) >= sizeof (*pMsg) ) { if ( AlignedWireRef < epicsUInt16 > ( pMsg->m_cmmd ) == REPEATER_REGISTER ) { register_new_client ( from, freeList ); /* * strip register client message */ pMsg++; size -= sizeof ( *pMsg ); if ( size==0 ) { continue; } } else if ( AlignedWireRef < epicsUInt16 > ( pMsg->m_cmmd ) == CA_PROTO_RSRV_IS_UP ) { if ( pMsg->m_available == 0u ) { pMsg->m_available = from.ia.sin_addr.s_addr; } } } else if ( size == 0 ) { register_new_client ( from, freeList ); continue; } fanOut ( from, pMsg, size, freeList ); } }
void Eiger::deinit (void) { osiSockRelease(); }
// // cac::cac () // cac::cac ( epicsMutex & mutualExclusionIn, epicsMutex & callbackControlIn, cacContextNotify & notifyIn ) : _refLocalHostName ( localHostNameCache.getReference () ), programBeginTime ( epicsTime::getCurrent() ), connTMO ( CA_CONN_VERIFY_PERIOD ), mutex ( mutualExclusionIn ), cbMutex ( callbackControlIn ), ipToAEngine ( ipAddrToAsciiEngine::allocate () ), timerQueue ( epicsTimerQueueActive::allocate ( false, lowestPriorityLevelAbove(epicsThreadGetPrioritySelf()) ) ), pUserName ( 0 ), pudpiiu ( 0 ), tcpSmallRecvBufFreeList ( 0 ), tcpLargeRecvBufFreeList ( 0 ), notify ( notifyIn ), initializingThreadsId ( epicsThreadGetIdSelf() ), initializingThreadsPriority ( epicsThreadGetPrioritySelf() ), maxRecvBytesTCP ( MAX_TCP ), maxContigFrames ( contiguousMsgCountWhichTriggersFlowControl ), beaconAnomalyCount ( 0u ), iiuExistenceCount ( 0u ), cacShutdownInProgress ( false ) { if ( ! osiSockAttach () ) { throwWithLocation ( udpiiu :: noSocket () ); } try { long status; /* * Certain os, such as HPUX, do not unblock a socket system call * when another thread asynchronously calls both shutdown() and * close(). To solve this problem we need to employ OS specific * mechanisms. */ epicsSignalInstallSigAlarmIgnore (); epicsSignalInstallSigPipeIgnore (); { char tmp[256]; size_t len; osiGetUserNameReturn gunRet; gunRet = osiGetUserName ( tmp, sizeof (tmp) ); if ( gunRet != osiGetUserNameSuccess ) { tmp[0] = '\0'; } len = strlen ( tmp ) + 1; this->pUserName = new char [ len ]; strncpy ( this->pUserName, tmp, len ); } this->_serverPort = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, static_cast <unsigned short> (CA_SERVER_PORT) ); status = envGetDoubleConfigParam ( &EPICS_CA_CONN_TMO, &this->connTMO ); if ( status ) { this->connTMO = CA_CONN_VERIFY_PERIOD; epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); errlogPrintf ( "EPICS \"%s\" double fetch failed\n", EPICS_CA_CONN_TMO.name ); errlogPrintf ( "Defaulting \"%s\" = %f\n", EPICS_CA_CONN_TMO.name, this->connTMO ); } long maxBytesAsALong; status = envGetLongConfigParam ( &EPICS_CA_MAX_ARRAY_BYTES, &maxBytesAsALong ); if ( status || maxBytesAsALong < 0 ) { errlogPrintf ( "cac: EPICS_CA_MAX_ARRAY_BYTES was not a positive integer\n" ); } else { /* allow room for the protocol header so that they get the array size they requested */ static const unsigned headerSize = sizeof ( caHdr ) + 2 * sizeof ( ca_uint32_t ); ca_uint32_t maxBytes = ( unsigned ) maxBytesAsALong; if ( maxBytes < 0xffffffff - headerSize ) { maxBytes += headerSize; } else { maxBytes = 0xffffffff; } if ( maxBytes < MAX_TCP ) { errlogPrintf ( "cac: EPICS_CA_MAX_ARRAY_BYTES was rounded up to %u\n", MAX_TCP ); } else { this->maxRecvBytesTCP = maxBytes; } } freeListInitPvt ( &this->tcpSmallRecvBufFreeList, MAX_TCP, 1 ); if ( ! this->tcpSmallRecvBufFreeList ) { throw std::bad_alloc (); } freeListInitPvt ( &this->tcpLargeRecvBufFreeList, this->maxRecvBytesTCP, 1 ); if ( ! this->tcpLargeRecvBufFreeList ) { throw std::bad_alloc (); } unsigned bufsPerArray = this->maxRecvBytesTCP / comBuf::capacityBytes (); if ( bufsPerArray > 1u ) { maxContigFrames = bufsPerArray * contiguousMsgCountWhichTriggersFlowControl; } } catch ( ... ) { osiSockRelease (); delete [] this->pUserName; if ( this->tcpSmallRecvBufFreeList ) { freeListCleanup ( this->tcpSmallRecvBufFreeList ); } if ( this->tcpLargeRecvBufFreeList ) { freeListCleanup ( this->tcpLargeRecvBufFreeList ); } this->timerQueue.release (); throw; } /* * load user configured tcp name server address list, * create virtual circuits, and add them to server table */ ELLLIST dest, tmpList; ellInit ( & dest ); ellInit ( & tmpList ); addAddrToChannelAccessAddressList ( &tmpList, &EPICS_CA_NAME_SERVERS, this->_serverPort, false ); removeDuplicateAddresses ( &dest, &tmpList, 0 ); epicsGuard < epicsMutex > guard ( this->mutex ); while ( osiSockAddrNode * pNode = reinterpret_cast < osiSockAddrNode * > ( ellGet ( & dest ) ) ) { tcpiiu * piiu = NULL; SearchDestTCP * pdst = new SearchDestTCP ( *this, pNode->addr ); this->registerSearchDest ( guard, * pdst ); bool newIIU = findOrCreateVirtCircuit ( guard, pNode->addr, cacChannel::priorityDefault, piiu, CA_UKN_MINOR_VERSION, pdst ); free ( pNode ); if ( newIIU ) { piiu->start ( guard ); } } }
cac::~cac () { // this blocks until the UDP thread exits so that // it will not sneak in any new clients // // lock intentionally not held here so that we dont deadlock // waiting for the UDP thread to exit while it is waiting to // get the lock. { epicsGuard < epicsMutex > cbGuard ( this->cbMutex ); epicsGuard < epicsMutex > guard ( this->mutex ); if ( this->pudpiiu ) { this->pudpiiu->shutdown ( cbGuard, guard ); // make sure no new tcp circuits are created this->cacShutdownInProgress = true; // // shutdown all tcp circuits // tsDLIter < tcpiiu > iter = this->circuitList.firstIter (); while ( iter.valid() ) { // this causes a clean shutdown to occur iter->unlinkAllChannels ( cbGuard, guard ); iter++; } } } // // wait for all tcp threads to exit // // this will block for oustanding sends to go out so dont // hold a lock while waiting // { epicsGuard < epicsMutex > guard ( this->mutex ); while ( this->iiuExistenceCount > 0 ) { epicsGuardRelease < epicsMutex > unguard ( guard ); this->iiuUninstall.wait (); } } if ( this->pudpiiu ) { delete this->pudpiiu; } freeListCleanup ( this->tcpSmallRecvBufFreeList ); freeListCleanup ( this->tcpLargeRecvBufFreeList ); delete [] this->pUserName; tsSLList < bhe > tmpBeaconList; this->beaconTable.removeAll ( tmpBeaconList ); while ( bhe * pBHE = tmpBeaconList.get() ) { pBHE->~bhe (); this->bheFreeList.release ( pBHE ); } this->timerQueue.release (); this->ipToAEngine.release (); // clean-up the list of un-notified msg objects while ( msgForMultiplyDefinedPV * msg = this->msgMultiPVList.get() ) { msg->~msgForMultiplyDefinedPV (); this->mdpvFreeList.release ( msg ); } errlogFlush (); osiSockRelease (); // its ok for channels and subscriptions to still // exist at this point. The user created them and // its his responsibility to clean them up. }
localHostName::~localHostName () { if ( this->attachedToSockLib ) { osiSockRelease (); } }