Пример #1
0
void BlockingTCPAcceptor::destroy() {
    SOCKET sock;
    {
        Lock guard(_mutex);
        if(_destroyed) return;
        _destroyed = true;

        sock = _serverSocketChannel;
        _serverSocketChannel = INVALID_SOCKET;
    }

    if(sock!=INVALID_SOCKET) {
        char ipAddrStr[48];
        ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr));
        LOG(logLevelDebug, "Stopped accepting connections at %s.", ipAddrStr);

        switch(epicsSocketSystemCallInterruptMechanismQuery())
        {
        case esscimqi_socketBothShutdownRequired:
            shutdown(sock, SHUT_RDWR);
            epicsSocketDestroy(sock);
            _thread.exitWait();
            break;
        case esscimqi_socketSigAlarmRequired:
            LOG(logLevelError, "SigAlarm close not implemented for this target\n");
        case esscimqi_socketCloseRequired:
            epicsSocketDestroy(sock);
            _thread.exitWait();
            break;
        }
    }
}
void AbstractResponseHandler::handleResponse(osiSockAddr* responseFrom,
        Transport::shared_pointer const & /*transport*/, int8 version, int8 command,
        size_t payloadSize, ByteBuffer* payloadBuffer) {
    if(_debugLevel >= 3) {   // TODO make a constant of sth (0 - off, 1 - debug, 2 - more/trace, 3 - messages)
        char ipAddrStr[48];
        ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr));

        ostringstream prologue;
        prologue<<"Message [0x"<<hex<<(int)command<<", v0x"<<hex;
        prologue<<(int)version<<"] received from "<<ipAddrStr;

        hexDump(prologue.str(), _description,
                (const int8*)payloadBuffer->getArray(),
                payloadBuffer->getPosition(), static_cast<int>(payloadSize));
    }
}
Пример #3
0
/*
 * removeDuplicateAddresses ()
 */
extern "C" void epicsShareAPI removeDuplicateAddresses 
    ( ELLLIST *pDestList, ELLLIST *pSrcList, int silent )
{
    ELLNODE *pRawNode;

    while ( (pRawNode  = ellGet ( pSrcList ) ) ) {
		STATIC_ASSERT ( offsetof (osiSockAddrNode, node) == 0 );
		osiSockAddrNode *pNode = reinterpret_cast <osiSockAddrNode *> ( pRawNode );
        osiSockAddrNode *pTmpNode;

        if ( pNode->addr.sa.sa_family == AF_INET ) {

            pTmpNode = (osiSockAddrNode *) ellFirst (pDestList);    // X aCC 749
            while ( pTmpNode ) {
                if (pTmpNode->addr.sa.sa_family == AF_INET) {
                    if ( pNode->addr.ia.sin_addr.s_addr == pTmpNode->addr.ia.sin_addr.s_addr && 
                            pNode->addr.ia.sin_port == pTmpNode->addr.ia.sin_port ) {
						if ( ! silent ) {
                            char buf[64];
                            ipAddrToDottedIP ( &pNode->addr.ia, buf, sizeof (buf) );
							fprintf ( stderr, 
								"Warning: Duplicate EPICS CA Address list entry \"%s\" discarded\n", buf );
						}
                        free (pNode);
                        pNode = NULL;
                        break;
                    }
                }
                pTmpNode = (osiSockAddrNode *) ellNext (&pTmpNode->node); // X aCC 749
            }
            if (pNode) {
                ellAdd (pDestList, &pNode->node);
            }
        }
        else {
            ellAdd (pDestList, &pNode->node);
        }
    }
}
SOCKET BlockingTCPConnector::tryConnect(osiSockAddr& address, int tries) {

    char strBuffer[64];
    ipAddrToDottedIP(&address.ia, strBuffer, sizeof(strBuffer));

    for(int tryCount = 0; tryCount<tries; tryCount++) {

        LOG(logLevelDebug,
            "Opening socket to PVA server %s, attempt %d.",
            strBuffer, tryCount+1);

        SOCKET socket = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (socket == INVALID_SOCKET)
        {
            epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
            std::ostringstream temp;
            temp<<"Socket create error: "<<strBuffer;
            THROW_EXCEPTION2(std::runtime_error, temp.str());
        }
        else {
            // TODO: use non-blocking connect() to have controllable timeout
            if(::connect(socket, &address.sa, sizeof(sockaddr))==0) {
                return socket;
            }
            else {
                epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                char saddr[32];
                sockAddrToDottedIP(&address.sa, saddr, sizeof(saddr));
                epicsSocketDestroy (socket);
                std::ostringstream temp;
                temp<<"error connecting to "<<saddr<<" : "<<strBuffer;
                throw std::runtime_error(temp.str());
            }
        }
    }
    return INVALID_SOCKET;
}
Пример #5
0
/*
 *  cas_send_bs_msg()
 *
 *  (channel access server send message)
 */
void cas_send_bs_msg ( struct client *pclient, int lock_needed )
{
    int status;

    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, (unsigned) pclient->addr.sin_addr.s_addr );
        }
        pclient->send.stk = 0u;
        return;
    }

    if ( lock_needed ) {
        SEND_LOCK ( pclient );
    }

    while ( pclient->send.stk && ! pclient->disconnect ) {
        status = send ( pclient->sock, pclient->send.buf, pclient->send.stk, 0 );
        if ( status >= 0 ) {
            unsigned transferSize = (unsigned) status;
            if ( transferSize >= pclient->send.stk ) {
                pclient->send.stk = 0;
                epicsTimeGetCurrent ( &pclient->time_at_last_send );
                break;
            }
            else {
                unsigned bytesLeft = pclient->send.stk - transferSize;
                memmove ( pclient->send.buf, &pclient->send.buf[transferSize], 
                    bytesLeft );
                pclient->send.stk = bytesLeft;
            }
        }
        else {
            int causeWasSocketHangup = 0;
            int anerrno = SOCKERRNO;
            char buf[64];

            if ( pclient->disconnect ) {
                pclient->send.stk = 0u;
                break;
            }

            if ( anerrno == SOCK_EINTR ) {
                continue;
            }

            if ( anerrno == SOCK_ENOBUFS ) {
                errlogPrintf (
                    "CAS: Out of network buffers, retrying send in 15 seconds\n" );
                epicsThreadSleep ( 15.0 );
                continue;
            }

            ipAddrToDottedIP ( &pclient->addr, buf, sizeof(buf) );

            if (    
                anerrno == SOCK_ECONNABORTED ||
                anerrno == SOCK_ECONNRESET ||
                anerrno == SOCK_EPIPE ||
                anerrno == SOCK_ETIMEDOUT ) {
                causeWasSocketHangup = 1;
            }
            else {
                char sockErrBuf[64];
                epicsSocketConvertErrnoToString ( 
                    sockErrBuf, sizeof ( sockErrBuf ) );
                errlogPrintf ( "CAS: TCP send to %s failed - %s\n",
                    buf, sockErrBuf);
            }
            pclient->disconnect = TRUE;
            pclient->send.stk = 0u;

            /*
             * wakeup the receive thread
             */
            if ( ! causeWasSocketHangup ) {
                enum epicsSocketSystemCallInterruptMechanismQueryInfo info  =
                    epicsSocketSystemCallInterruptMechanismQuery ();
                switch ( info ) {
                case esscimqi_socketCloseRequired:
                    if ( pclient->sock != INVALID_SOCKET ) {
                        epicsSocketDestroy ( pclient->sock );
                        pclient->sock = INVALID_SOCKET;
                    }
                    break;
                case esscimqi_socketBothShutdownRequired:
                    {
                        int status = shutdown ( pclient->sock, SHUT_RDWR );
                        if ( status ) {
                            char sockErrBuf[64];
                            epicsSocketConvertErrnoToString ( 
                                sockErrBuf, sizeof ( sockErrBuf ) );
                            errlogPrintf ("CAS: Socket shutdown error - %s\n", 
                                sockErrBuf );
                        }
                    }
                    break;
                case esscimqi_socketSigAlarmRequired:
                    epicsSignalRaiseSigAlarm ( pclient->tid );
                    break;
                default:
                    break;
                };
                break;
            }
        }
    }

    if ( lock_needed ) {
        SEND_UNLOCK(pclient);
    }

    DLOG ( 3, ( "------------------------------\n\n" ) );

    return;
}
Пример #6
0
/*
 *  cas_send_dg_msg()
 *
 *  (channel access server send udp message)
 */
void cas_send_dg_msg ( struct client * pclient )
{
    int status;
    int sizeDG;
    char * pDG; 
    caHdr * pMsg;

    if ( CASDEBUG > 2 && pclient->send.stk ) {
        errlogPrintf ( "CAS: Sending a udp message of %d bytes\n", pclient->send.stk );
    }

    SEND_LOCK ( pclient );

    if ( pclient->send.stk <= sizeof (caHdr) ) {
        SEND_UNLOCK(pclient);
        return;
    }

    pDG = pclient->send.buf;
    pMsg = ( caHdr * ) pDG;
    sizeDG = pclient->send.stk;
    assert ( ntohs ( pMsg->m_cmmd ) == CA_PROTO_VERSION );
    if ( CA_V411 ( pclient->minor_version_number ) ) {
        pMsg->m_cid = htonl ( pclient->seqNoOfReq );
        pMsg->m_dataType = htons ( sequenceNoIsValid );
    }
    else {
        pDG += sizeof (caHdr);
        sizeDG -= sizeof (caHdr);
    }

    status = sendto ( pclient->sock, pDG, sizeDG, 0,
       (struct sockaddr *)&pclient->addr, sizeof(pclient->addr) );
    if ( status >= 0 ) {
        if ( status >= sizeDG ) {
            epicsTimeGetCurrent ( &pclient->time_at_last_send );
        }
        else {
            errlogPrintf ( 
                "CAS: System failed to send entire udp frame?\n" );
        }
    }
    else {
        char sockErrBuf[64];
        char buf[128];
        epicsSocketConvertErrnoToString ( 
            sockErrBuf, sizeof ( sockErrBuf ) );
        ipAddrToDottedIP ( &pclient->addr, buf, sizeof(buf) );
        errlogPrintf( "CAS: UDP send to %s failed - %s\n",
            buf, sockErrBuf);
    }

    pclient->send.stk = 0u;

    /*
     * add placeholder for the first version message should it be needed
     */
    rsrv_version_reply ( pclient );

    SEND_UNLOCK(pclient);

    DLOG ( 3, ( "------------------------------\n\n" ) );

    return;
}
Пример #7
0
/*
 *  create_tcp_client ()
 */
struct client *create_tcp_client ( SOCKET sock )
{
    int                     status;
    struct client           *client;
    int                     intTrue = TRUE;
    osiSocklen_t            addrSize;
    unsigned                priorityOfEvents;

    /* socket passed in is destroyed here if unsuccessful */
    client = create_client ( sock, IPPROTO_TCP );
    if ( ! client ) {
        return NULL;
    }

    /*
     * 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 *) &intTrue, sizeof (intTrue) );
    if (status < 0) {
        errlogPrintf ( "CAS: TCP_NODELAY option set failed\n" );
        destroy_client ( client );
        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 *) &intTrue, sizeof (intTrue) );
    if ( status < 0 ) {
        errlogPrintf ( "CAS: SO_KEEPALIVE option set failed\n" );
        destroy_client ( client );
        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" );
        destroy_client ( client );
        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" );
        destroy_client ( client );
        return NULL;
    }
#endif
   
    addrSize = sizeof ( client->addr );
    status = getpeername ( sock, (struct sockaddr *)&client->addr,
                    &addrSize );
    if ( status < 0 ) {
        epicsPrintf ("CAS: peer address fetch failed\n");
        destroy_tcp_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_tcp_client (client);
        return NULL;
    }

    status = db_add_extra_labor_event ( client->evuser, rsrv_extra_labor, client );
    if (status != DB_EVENT_OK) {
        errlogPrintf("CAS: unable to setup the event facility\n");
        destroy_tcp_client (client);
        return NULL;
    }

    {
        epicsThreadBooleanStatus    tbs;

        tbs  = epicsThreadHighestPriorityLevelBelow ( epicsThreadPriorityCAServerLow, &priorityOfEvents );
        if ( tbs != epicsThreadBooleanStatusSuccess ) {
            priorityOfEvents = epicsThreadPriorityCAServerLow;
        }
    }

    status = db_start_events ( client->evuser, "CAS-event", 
                NULL, NULL, priorityOfEvents ); 
    if ( status != DB_EVENT_OK ) {
        errlogPrintf ( "CAS: unable to start the event facility\n" );
        destroy_tcp_client ( client );
        return NULL;
    }

    /*
     * add first version message should it be needed
     */
    rsrv_version_reply ( client );

    if ( CASDEBUG > 0 ) {
        char buf[64];
        ipAddrToDottedIP ( &client->addr, buf, sizeof(buf) );
        errlogPrintf ( "CAS: conn req from %s\n", buf );
    }

    return client;
}
Пример #8
0
/*
 *  log_one_client ()
 */
static void log_one_client (struct client *client, unsigned level)
{
    char                    *pproto;
    double                  send_delay;
    double                  recv_delay;
    char                    *state[] = {"up", "down"};
    epicsTimeStamp          current;
    char                    clientHostName[256];

    ipAddrToDottedIP (&client->addr, clientHostName, sizeof(clientHostName));

    if(client->proto == IPPROTO_UDP){
        pproto = "UDP";
    }
    else if(client->proto == IPPROTO_TCP){
        pproto = "TCP";
    }
    else{
        pproto = "UKN";
    }

    epicsTimeGetCurrent(&current);
    send_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_send);
    recv_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_recv);

    printf ( "%s %s(%s): User=\"%s\", V%u.%u, %d Channels, Priority=%u\n", 
        pproto,
        clientHostName,
        client->pHostName ? client->pHostName : "",
        client->pUserName ? client->pUserName : "",
        CA_MAJOR_PROTOCOL_REVISION,
        client->minor_version_number,
        ellCount(&client->chanList) + 
            ellCount(&client->chanPendingUpdateARList),
        client->priority );
    if ( level >= 1 ) {
        printf ("\tTask Id=%p, Socket FD=%d\n", 
            (void *) client->tid, client->sock); 
        printf( 
        "\tSecs since last send %6.2f, Secs since last receive %6.2f\n", 
            send_delay, recv_delay);
        printf( 
        "\tUnprocessed request bytes=%u, Undelivered response bytes=%u\n", 
            client->recv.cnt - client->recv.stk,
            client->send.stk ); 
        printf( 
        "\tState=%s%s%s\n", 
            state[client->disconnect?1:0],
            client->send.type == mbtLargeTCP ? " jumbo-send-buf" : "",
            client->recv.type == mbtLargeTCP ? " jumbo-recv-buf" : "");
    }

    if ( level >= 2u ) {
        unsigned bytes_reserved = 0;
        bytes_reserved += sizeof(struct client);
        bytes_reserved += countChanListBytes ( 
                            client, & client->chanList );
        bytes_reserved += countChanListBytes ( 
                        client, & client->chanPendingUpdateARList );
        printf( "\t%d bytes allocated\n", bytes_reserved);
        showChanList ( client, & client->chanList );
        showChanList ( client, & client->chanPendingUpdateARList );
        printf("\n");
    }

    if ( level >= 3u ) {
        printf( "\tSend Lock\n");
        epicsMutexShow(client->lock,1);
        printf( "\tPut Notify Lock\n");
        epicsMutexShow (client->putNotifyLock,1);
        printf( "\tAddress Queue Lock\n");
        epicsMutexShow (client->chanListLock,1);
        printf( "\tEvent Queue Lock\n");
        epicsMutexShow (client->eventqLock,1);
        printf( "\tBlock Semaphore\n");
        epicsEventShow (client->blockSem,1);
    }
}
Пример #9
0
/*
 * Read from the TCP port
 */
static asynStatus readIt(void *drvPvt, asynUser *pasynUser,
                         char *data, size_t maxchars,size_t *nbytesTransfered,int *gotEom)
{
    ttyController_t *tty = (ttyController_t *)drvPvt;
    int thisRead;
    int readPollmsec;
    int reason = 0;
    epicsTimeStamp startTime;
    epicsTimeStamp endTime;
    asynStatus status = asynSuccess;

    assert(tty);
    asynPrint(pasynUser, ASYN_TRACE_FLOW,
              "%s read.\n", tty->IPDeviceName);
    if (tty->fd == INVALID_SOCKET) {
        if (tty->flags & FLAG_CONNECT_PER_TRANSACTION) {
            if ((status = connectIt(drvPvt, pasynUser)) != asynSuccess)
                return status;
        }
        else {
            epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "%s disconnected:", tty->IPDeviceName);
            return asynError;
        }
    }
    if (maxchars <= 0) {
        epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                      "%s maxchars %d. Why <=0?",tty->IPDeviceName,(int)maxchars);
        return asynError;
    }
    readPollmsec = (int) (pasynUser->timeout * 1000.0);
    if (readPollmsec == 0) readPollmsec = 1;
    if (readPollmsec < 0) readPollmsec = -1;
#ifdef USE_SOCKTIMEOUT
    {
        struct timeval tv;
        tv.tv_sec = readPollmsec / 1000;
        tv.tv_usec = (readPollmsec % 1000) * 1000;
        if (setsockopt(tty->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv) < 0) {
            epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "Can't set %s socket receive timeout: %s",
                          tty->IPDeviceName, strerror(SOCKERRNO));
            status = asynError;
        }
    }
#endif
    if (gotEom) *gotEom = 0;
#ifdef USE_POLL
    {
        struct pollfd pollfd;
        pollfd.fd = tty->fd;
        pollfd.events = POLLIN;
        epicsTimeGetCurrent(&startTime);
        while (poll(&pollfd, 1, readPollmsec) < 0) {
            if (errno != EINTR) {
                epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                              "Poll() failed: %s", strerror(errno));
                return asynError;
            }
            epicsTimeGetCurrent(&endTime);
            if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000. > readPollmsec) break;
        }
    }
#endif
    if (tty->socketType == SOCK_DGRAM) {
        /* We use recvfrom() for SOCK_DRAM so we can print the source address with ASYN_TRACEIO_DRIVER */
        osiSockAddr oa;
        unsigned int addrlen = sizeof(oa.ia);
        thisRead = recvfrom(tty->fd, data, (int)maxchars, 0, &oa.sa, &addrlen);
        if (thisRead > 0) {
            if (pasynTrace->getTraceMask(pasynUser) & ASYN_TRACEIO_DRIVER) {
                char inetBuff[32];
                ipAddrToDottedIP(&oa.ia, inetBuff, sizeof(inetBuff));
                asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead,
                            "%s (from %s) read %d\n",
                            tty->IPDeviceName, inetBuff, thisRead);
            }
            tty->nRead += (unsigned long)thisRead;
        }
    } else {
        thisRead = recv(tty->fd, data, (int)maxchars, 0);
        if (thisRead > 0) {
            asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead,
                        "%s read %d\n", tty->IPDeviceName, thisRead);
            tty->nRead += (unsigned long)thisRead;
        }
    }
    if (thisRead < 0) {
        int should_close = (tty->userFlags & USERFLAG_CLOSE_ON_READ_TIMEOUT) ||
                           ((SOCKERRNO != SOCK_EWOULDBLOCK) && (SOCKERRNO != SOCK_EINTR));
        if (should_close) {
            epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "%s read error: %s",
                          tty->IPDeviceName, strerror(SOCKERRNO));
            closeConnection(pasynUser,tty,"Read error");
            status = asynError;
        } else {
            epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                          "%s timeout: %s",
                          tty->IPDeviceName, strerror(SOCKERRNO));
            status = asynTimeout;
        }
    }
    /* If recv() returns 0 on a SOCK_STREAM (TCP) socket, the connection has closed */
    if ((thisRead == 0) && (tty->socketType == SOCK_STREAM)) {
        epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize,
                      "%s connection closed",
                      tty->IPDeviceName);
        closeConnection(pasynUser,tty,"Read from broken connection");
        reason |= ASYN_EOM_END;
    }
    if (thisRead < 0)
        thisRead = 0;
    *nbytesTransfered = thisRead;
    /* If there is room add a null byte */
    if (thisRead < (int) maxchars)
        data[thisRead] = 0;
    else
        reason |= ASYN_EOM_CNT;
    if (gotEom) *gotEom = reason;
    return status;
}
Пример #10
0
int BlockingTCPAcceptor::initialize() {

    char ipAddrStr[48];
    ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr));

    int tryCount = 0;
    while(tryCount<2) {
        char strBuffer[64];

        LOG(logLevelDebug, "Creating acceptor to %s.", ipAddrStr);

        _serverSocketChannel = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(_serverSocketChannel==INVALID_SOCKET) {
            epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
            ostringstream temp;
            temp<<"Socket create error: "<<strBuffer;
            LOG(logLevelError, "%s", temp.str().c_str());
            THROW_BASE_EXCEPTION(temp.str().c_str());
        }
        else {

            //epicsSocketEnableAddressReuseDuringTimeWaitState(_serverSocketChannel);

            // try to bind
            int retval = ::bind(_serverSocketChannel, &_bindAddress.sa, sizeof(sockaddr));
            if(retval<0) {
                epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                LOG(logLevelDebug, "Socket bind error: %s.", strBuffer);
                if(_bindAddress.ia.sin_port!=0) {
                    // failed to bind to specified bind address,
                    // try to get port dynamically, but only once
                    LOG(
                        logLevelDebug,
                        "Configured TCP port %d is unavailable, trying to assign it dynamically.",
                        ntohs(_bindAddress.ia.sin_port));
                    _bindAddress.ia.sin_port = htons(0);
                }
                else {
                    epicsSocketDestroy(_serverSocketChannel);
                    break; // exit while loop
                }
            }
            else { // if(retval<0)
                // bind succeeded

                // update bind address, if dynamically port selection was used
                if(ntohs(_bindAddress.ia.sin_port)==0) {
                    osiSocklen_t sockLen = sizeof(sockaddr);
                    // read the actual socket info
                    retval = ::getsockname(_serverSocketChannel, &_bindAddress.sa, &sockLen);
                    if(retval<0) {
                        // error obtaining port number
                        epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                        LOG(logLevelDebug, "getsockname error: %s", strBuffer);
                    }
                    else {
                        LOG(
                            logLevelInfo,
                            "Using dynamically assigned TCP port %d.",
                            ntohs(_bindAddress.ia.sin_port));
                    }
                }

                retval = ::listen(_serverSocketChannel, 4);
                if(retval<0) {
                    epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                    ostringstream temp;
                    temp<<"Socket listen error: "<<strBuffer;
                    LOG(logLevelError, "%s", temp.str().c_str());
                    THROW_BASE_EXCEPTION(temp.str().c_str());
                }

                _thread.start();

                // all OK, return
                return ntohs(_bindAddress.ia.sin_port);
            } // successful bind
        } // successfully obtained socket
        tryCount++;
    } // while

    ostringstream temp;
    temp<<"Failed to create acceptor to "<<ipAddrStr;
    THROW_BASE_EXCEPTION(temp.str().c_str());
}
Пример #11
0
void BlockingTCPAcceptor::run() {
    // rise level if port is assigned dynamically
    char ipAddrStr[48];
    ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr));
    LOG(logLevelDebug, "Accepting connections at %s.", ipAddrStr);

    bool socketOpen = true;
    char strBuffer[64];

    while(socketOpen) {

        {
            Lock guard(_mutex);
            if (_destroyed)
                break;
        }

        osiSockAddr address;
        osiSocklen_t len = sizeof(sockaddr);

        SOCKET newClient = epicsSocketAccept(_serverSocketChannel, &address.sa, &len);
        if(newClient!=INVALID_SOCKET) {
            // accept succeeded
            ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr));
            LOG(logLevelDebug, "Accepted connection from PVA client: %s.", ipAddrStr);

            // enable TCP_NODELAY (disable Nagle's algorithm)
            int optval = 1; // true
            int retval = ::setsockopt(newClient, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(int));
            if(retval<0) {
                epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                LOG(logLevelDebug, "Error setting TCP_NODELAY: %s.", strBuffer);
            }

            // enable TCP_KEEPALIVE
            retval = ::setsockopt(newClient, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(int));
            if(retval<0) {
                epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                LOG(logLevelDebug, "Error setting SO_KEEPALIVE: %s.", strBuffer);
            }

            // do NOT tune socket buffer sizes, this will disable auto-tunning

            // get TCP send buffer size
            osiSocklen_t intLen = sizeof(int);
            int _socketSendBufferSize;
            retval = getsockopt(newClient, SOL_SOCKET, SO_SNDBUF, (char *)&_socketSendBufferSize, &intLen);
            if(retval<0) {
                epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
                LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer);
            }

            /**
             * Create transport, it registers itself to the registry.
             */
            detail::BlockingServerTCPTransportCodec::shared_pointer transport =
                detail::BlockingServerTCPTransportCodec::create(
                    _context,
                    newClient,
                    _responseHandler,
                    _socketSendBufferSize,
                    _receiveBufferSize);

            // validate connection
            if(!validateConnection(transport, ipAddrStr)) {
                // TODO
                // wait for negative response to be sent back and
                // hold off the client for retrying at very high rate
                epicsThreadSleep(1.0);

                transport->close();
                LOG(
                    logLevelDebug,
                    "Connection to PVA client %s failed to be validated, closing it.",
                    ipAddrStr);
                continue;
            }

            LOG(logLevelDebug, "Serving to PVA client: %s.", ipAddrStr);

        }// accept succeeded
        else
            socketOpen = false;
    } // while
}
Пример #12
0
/*
 *  logClientCreate()
 */
logClientId epicsShareAPI logClientCreate (
    struct in_addr server_addr, unsigned short server_port)
{
    epicsTimeStamp begin, current;
    logClient *pClient;
    double diff;

    pClient = calloc (1, sizeof (*pClient));
    if (pClient==NULL) {
        return NULL;
    }

    pClient->addr.sin_family = AF_INET;
    pClient->addr.sin_addr = server_addr;
    pClient->addr.sin_port = htons(server_port);
    ipAddrToDottedIP (&pClient->addr, pClient->name, sizeof(pClient->name));

    pClient->mutex = epicsMutexCreate ();
    if ( ! pClient->mutex ) {
        free ( pClient );
        return NULL;
    }

    pClient->sock = INVALID_SOCKET;
    pClient->connected = 0u;
    pClient->connFailStatus = 0;
    pClient->shutdown = 0;
    pClient->shutdownConfirm = 0;

    epicsAtExit (logClientDestroy, (void*) pClient);
    
    pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty);
    if ( ! pClient->stateChangeNotify ) {
        epicsMutexDestroy ( pClient->mutex );
        free ( pClient );
        return NULL;
    }
   
    pClient->restartThreadId = epicsThreadCreate (
        "logRestart", epicsThreadPriorityLow, 
        epicsThreadGetStackSize(epicsThreadStackSmall),
        logClientRestart, pClient );
    if ( pClient->restartThreadId == NULL ) {
        epicsMutexDestroy ( pClient->mutex );
        epicsEventDestroy ( pClient->stateChangeNotify );
        free (pClient);
        fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");
        return NULL;
    }

    /*
     * attempt to synchronize with circuit connect
     */
    epicsTimeGetCurrent ( & begin );
    epicsMutexMustLock ( pClient->mutex );
    do {
        epicsMutexUnlock ( pClient->mutex );
        epicsEventWaitWithTimeout ( 
            pClient->stateChangeNotify, 
            LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 ); 
        epicsTimeGetCurrent ( & current );
        diff = epicsTimeDiffInSeconds ( & current, & begin );
        epicsMutexMustLock ( pClient->mutex );
    }
    while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
    epicsMutexUnlock ( pClient->mutex );

    if ( ! pClient->connected ) {
        fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n",
            pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT );
    }
        
    return (void *) pClient;
}
Transport::shared_pointer BlockingTCPConnector::connect(std::tr1::shared_ptr<ClientChannelImpl> const & client,
        ResponseHandler::shared_pointer const & responseHandler, osiSockAddr& address,
        int8 transportRevision, int16 priority) {

    SOCKET socket = INVALID_SOCKET;

    char ipAddrStr[64];
    ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr));

    Context::shared_pointer context = _context.lock();

    TransportRegistry::Reservation rsvp(context->getTransportRegistry(),
                                        address, priority);
    // we are now blocking any connect() to this destination (address and prio)
    // concurrent connect() to other destination is allowed.
    // This prevents us from opening duplicate connections.

    Transport::shared_pointer transport = context->getTransportRegistry()->get(address, priority);
    if(transport.get()) {
        LOG(logLevelDebug,
            "Reusing existing connection to PVA server: %s.",
            ipAddrStr);
        if (transport->acquire(client))
            return transport;
    }

    try {
        LOG(logLevelDebug, "Connecting to PVA server: %s.", ipAddrStr);

        socket = tryConnect(address, 3);

        LOG(logLevelDebug, "Socket connected to PVA server: %s.", ipAddrStr);

        // enable TCP_NODELAY (disable Nagle's algorithm)
        int optval = 1; // true
        int retval = ::setsockopt(socket, IPPROTO_TCP, TCP_NODELAY,
                                  (char *)&optval, sizeof(int));
        if(retval<0) {
            char errStr[64];
            epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
            LOG(logLevelWarn, "Error setting TCP_NODELAY: %s.", errStr);
        }

        // enable TCP_KEEPALIVE
        retval = ::setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE,
                              (char *)&optval, sizeof(int));
        if(retval<0)
        {
            char errStr[64];
            epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
            LOG(logLevelWarn, "Error setting SO_KEEPALIVE: %s.", errStr);
        }

        // TODO tune buffer sizes?! Win32 defaults are 8k, which is OK

        // create transport
        // TODO introduce factory
        // get TCP send buffer size
        osiSocklen_t intLen = sizeof(int);
        int _socketSendBufferSize;
        retval = getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&_socketSendBufferSize, &intLen);
        if(retval<0) {
            char strBuffer[64];
            epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer));
            LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer);
        }

        // create() also adds to context connection pool _context->getTransportRegistry()
        transport = detail::BlockingClientTCPTransportCodec::create(
                    context, socket, responseHandler, _receiveBufferSize, _socketSendBufferSize,
                    client, transportRevision, _heartbeatInterval, priority);

        // verify
        if(!transport->verify(5000)) {
            LOG(
                        logLevelDebug,
                        "Connection to PVA server %s failed to be validated, closing it.",
                        ipAddrStr);

            std::ostringstream temp;
            temp<<"Failed to verify TCP connection to '"<<ipAddrStr<<"'.";
            THROW_BASE_EXCEPTION(temp.str().c_str());
        }

        LOG(logLevelDebug, "Connected to PVA server: %s.", ipAddrStr);

        return transport;
    } catch(std::exception&) {
        if(transport.get())
            transport->close();
        else if(socket!=INVALID_SOCKET)
            epicsSocketDestroy(socket);
        throw;
    }
}
Пример #14
0
/*
 *  RSRV_ONLINE_NOTIFY_TASK
 */
void rsrv_online_notify_task(void *pParm)
{
    unsigned                    priorityOfSelf = epicsThreadGetPrioritySelf ();
    osiSockAddrNode             *pNode;
    double                      delay;
    double                      maxdelay;
    long                        longStatus;
    double                      maxPeriod;
    caHdr                       msg;
    int                         status;
    SOCKET                      sock;
    int                         intTrue = TRUE;
    unsigned short              port;
    ca_uint32_t                 beaconCounter = 0;
    char                        * pStr;
    int                         autoBeaconAddr;
    ELLLIST                     autoAddrList;
    char                        buf[16];
    unsigned                    priorityOfUDP;
    epicsThreadBooleanStatus    tbs;
    epicsThreadId               tid;
    
    taskwdInsert (epicsThreadGetIdSelf(),NULL,NULL);
    
    if ( envGetConfigParamPtr ( & EPICS_CAS_BEACON_PERIOD ) ) {
        longStatus = envGetDoubleConfigParam ( & EPICS_CAS_BEACON_PERIOD, & maxPeriod );
    }
    else {
        longStatus = envGetDoubleConfigParam ( & EPICS_CA_BEACON_PERIOD, & maxPeriod );
    }
    if (longStatus || maxPeriod<=0.0) {
        maxPeriod = 15.0;
        epicsPrintf ("EPICS \"%s\" float fetch failed\n",
                        EPICS_CAS_BEACON_PERIOD.name);
        epicsPrintf ("Setting \"%s\" = %f\n",
            EPICS_CAS_BEACON_PERIOD.name, maxPeriod);
    }
    
    delay = 0.02; /* initial beacon period in sec */
    maxdelay = maxPeriod;
    
    /* 
     *  Open the socket.
     *  Use ARPA Internet address format and datagram socket.
     *  Format described in <sys/socket.h>.
     */
    if ( (sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
        errlogPrintf ("CAS: online socket creation error\n");
        epicsThreadSuspendSelf ();
    }
    
    status = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, 
                (char *)&intTrue, sizeof(intTrue));
    if (status<0) {
        errlogPrintf ("CAS: online socket set up error\n");
        epicsThreadSuspendSelf ();
    }

    {
        /*
         * this connect is to supress a warning message on Linux
         * when we shutdown the read side of the socket. If it
         * fails (and it will on old ip kernels) we just ignore 
         * the failure.
         */
        osiSockAddr sockAddr;
        sockAddr.ia.sin_family = AF_UNSPEC;
        sockAddr.ia.sin_port = htons ( 0 );
        sockAddr.ia.sin_addr.s_addr = htonl (0);
        connect ( sock, & sockAddr.sa, sizeof ( sockAddr.sa ) );
        shutdown ( sock, SHUT_RD );
    }
    
    memset((char *)&msg, 0, sizeof msg);
    msg.m_cmmd = htons (CA_PROTO_RSRV_IS_UP);
    msg.m_count = htons (ca_server_port);
    msg.m_dataType = htons (CA_MINOR_PROTOCOL_REVISION);
    
    ellInit ( & beaconAddrList );
    ellInit ( & autoAddrList );

    pStr = envGetConfigParam(&EPICS_CAS_AUTO_BEACON_ADDR_LIST, sizeof(buf), buf);
    if ( ! pStr ) {
	    pStr = envGetConfigParam(&EPICS_CA_AUTO_ADDR_LIST, sizeof(buf), buf);
    }
	if (pStr) {
		if (strstr(pStr,"no")||strstr(pStr,"NO")) {
			autoBeaconAddr = FALSE;
		}
		else if (strstr(pStr,"yes")||strstr(pStr,"YES")) {
			autoBeaconAddr = TRUE;
		}
		else {
			fprintf(stderr, 
		"CAS: EPICS_CA(S)_AUTO_ADDR_LIST = \"%s\"? Assuming \"YES\"\n", pStr);
			autoBeaconAddr = TRUE;
		}
	}
	else {
		autoBeaconAddr = TRUE;
	}

    /*
     * load user and auto configured
     * broadcast address list
     */
    if (envGetConfigParamPtr(&EPICS_CAS_BEACON_PORT)) {
        port = envGetInetPortConfigParam (&EPICS_CAS_BEACON_PORT, 
            (unsigned short) CA_REPEATER_PORT );
    }
    else {
        port = envGetInetPortConfigParam (&EPICS_CA_REPEATER_PORT, 
            (unsigned short) CA_REPEATER_PORT );
    }

    /*
     * discover beacon addresses associated with this interface
     */
    if ( autoBeaconAddr ) {
        osiSockAddr addr;
		ELLLIST tmpList;

		ellInit ( &tmpList );
        addr.ia.sin_family = AF_UNSPEC;
        osiSockDiscoverBroadcastAddresses (&tmpList, sock, &addr); 
        forcePort ( &tmpList, port );
		removeDuplicateAddresses ( &autoAddrList, &tmpList, 1 );
    }
            
    /*
     * by default use EPICS_CA_ADDR_LIST for the
     * beacon address list
     */
    {
        const ENV_PARAM *pParam;
        
        if (envGetConfigParamPtr(&EPICS_CAS_INTF_ADDR_LIST) || 
            envGetConfigParamPtr(&EPICS_CAS_BEACON_ADDR_LIST)) {
            pParam = &EPICS_CAS_BEACON_ADDR_LIST;
        }
        else {
            pParam = &EPICS_CA_ADDR_LIST;
        }
    
        /* 
         * add in the configured addresses
         */
        addAddrToChannelAccessAddressList (
            &autoAddrList, pParam, port,  pParam == &EPICS_CA_ADDR_LIST );
    }
 
    removeDuplicateAddresses ( &beaconAddrList, &autoAddrList, 0 );

    if ( ellCount ( &beaconAddrList ) == 0 ) {
        errlogPrintf ("The CA server's beacon address list was empty after initialization?\n");
    }
  
#   ifdef DEBUG
        printChannelAccessAddressList (&beaconAddrList);
#   endif

    tbs  = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfUDP );
    if ( tbs != epicsThreadBooleanStatusSuccess ) {
        priorityOfUDP = priorityOfSelf;
    }

    casudp_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
    casudp_ctl = ctlPause;

    tid = epicsThreadCreate ( "CAS-UDP", priorityOfUDP,
        epicsThreadGetStackSize (epicsThreadStackMedium),
        cast_server, 0 );
    if ( tid == 0 ) {
        epicsPrintf ( "CAS: unable to start UDP daemon thread\n" );
    }

    epicsEventMustWait(casudp_startStopEvent);
    epicsEventSignal(beacon_startStopEvent);

    while (TRUE) {
        pNode = (osiSockAddrNode *) ellFirst (&beaconAddrList);
        while (pNode) {
            char buf[64];

            status = connect (sock, &pNode->addr.sa, 
                sizeof(pNode->addr.sa));
            if (status<0) {
                char sockErrBuf[64];
                epicsSocketConvertErrnoToString ( 
                    sockErrBuf, sizeof ( sockErrBuf ) );
                ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
                errlogPrintf ( "%s: CA beacon routing (connect to \"%s\") error was \"%s\"\n",
                    __FILE__, buf, sockErrBuf);
            }
            else {
                struct sockaddr_in if_addr;

                osiSocklen_t size = sizeof (if_addr);
                status = getsockname (sock, (struct sockaddr *) &if_addr, &size);
                if (status<0) {
                    char sockErrBuf[64];
                    epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
                    errlogPrintf ( "%s: CA beacon routing (getsockname) error was \"%s\"\n",
                        __FILE__, sockErrBuf);
                }
                else if (if_addr.sin_family==AF_INET) {
                    msg.m_available = if_addr.sin_addr.s_addr;
                    msg.m_cid = htonl ( beaconCounter );

                    status = send (sock, (char *)&msg, sizeof(msg), 0);
                    if (status < 0) {
                        char sockErrBuf[64];
                        epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
                        ipAddrToDottedIP (&pNode->addr.ia, buf, sizeof(buf));
                        errlogPrintf ( "%s: CA beacon (send to \"%s\") error was \"%s\"\n",
                            __FILE__, buf, sockErrBuf);
                    }
                    else {
                        assert (status == sizeof(msg));
                    }
                }
            }
            pNode = (osiSockAddrNode *) pNode->node.next;
        }

        epicsThreadSleep(delay);
        if (delay<maxdelay) {
            delay *= 2.0;
            if (delay>maxdelay) {
                delay = maxdelay;
            }
        }

        beaconCounter++; /* expected to overflow */

        while (beacon_ctl == ctlPause) {
            epicsThreadSleep(0.1);
            delay = 0.02; /* Restart beacon timing if paused */
        }
    }
}
Пример #15
0
/*
 * CAST_SERVER
 *
 * service UDP messages
 * 
 */
void cast_server(void *pParm)
{
    struct sockaddr_in  sin;    
    int                 status;
    int                 count=0;
    struct sockaddr_in  new_recv_addr;
    osiSocklen_t        recv_addr_size;
    unsigned short      port;
    osiSockIoctl_t      nchars;

    if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) {
        port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT, 
            (unsigned short) CA_SERVER_PORT );
    }
    else {
        port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, 
            (unsigned short) CA_SERVER_PORT );
    }

    recv_addr_size = sizeof(new_recv_addr);

    if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) {
        epicsSocketDestroy ( IOC_cast_sock );
    }

    /* 
     *  Open the socket.
     *  Use ARPA Internet address format and datagram socket.
     */

    if ( ( IOC_cast_sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0) ) == INVALID_SOCKET ) {
        epicsPrintf ("CAS: cast socket creation error\n");
        epicsThreadSuspendSelf ();
    }

    /*
     * 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");
        }
    }
#endif

    epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock );
    
    /*  Zero the sock_addr structure */
    memset((char *)&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = htons(port);
    
    /* get server's Internet address */
    if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( 
            sockErrBuf, sizeof ( sockErrBuf ) );
        epicsPrintf ("CAS: UDP server port bind error was \"%s\"\n", sockErrBuf );
        epicsSocketDestroy ( IOC_cast_sock );
        epicsThreadSuspendSelf ();
    }

    /*
     * setup new client structure but reuse old structure if
     * possible
     *
     */
    while ( TRUE ) {
        prsrv_cast_client = create_client ( IOC_cast_sock, IPPROTO_UDP );
        if ( prsrv_cast_client ) {
            break;
        }
        epicsThreadSleep(300.0);
    }

    casAttachThreadToClient ( prsrv_cast_client );

    /*
     * add placeholder for the first version message should it be needed
     */
    rsrv_version_reply ( prsrv_cast_client );

    epicsEventSignal(casudp_startStopEvent);

    while (TRUE) {
        status = recvfrom (
            IOC_cast_sock,
            prsrv_cast_client->recv.buf,
            prsrv_cast_client->recv.maxstk,
            0,
            (struct sockaddr *)&new_recv_addr, 
            &recv_addr_size);
        if (status < 0) {
            if (SOCKERRNO != SOCK_EINTR) {
                char sockErrBuf[64];
                epicsSocketConvertErrnoToString ( 
                    sockErrBuf, sizeof ( sockErrBuf ) );
                epicsPrintf ("CAS: UDP recv error (errno=%s)\n",
                        sockErrBuf);
                epicsThreadSleep(1.0);
            }
        }
        else if (casudp_ctl == ctlRun) {
            prsrv_cast_client->recv.cnt = (unsigned) status;
            prsrv_cast_client->recv.stk = 0ul;
            epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv);

            prsrv_cast_client->minor_version_number = 0;
            prsrv_cast_client->seqNoOfReq = 0;

            /*
             * If we are talking to a new client flush to the old one 
             * in case we are holding UDP messages waiting to 
             * see if the next message is for this same client.
             */
            if (prsrv_cast_client->send.stk>sizeof(caHdr)) {
                status = memcmp( (void *)&prsrv_cast_client->addr, (void *)&new_recv_addr, recv_addr_size);
                if(status){     
                    /* 
                     * if the address is different 
                     */
                    cas_send_dg_msg(prsrv_cast_client);
                    prsrv_cast_client->addr = new_recv_addr;
                }
            }
            else {
                prsrv_cast_client->addr = new_recv_addr;
            }

            if (CASDEBUG>1) {
                char    buf[40];
    
                ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));
                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->chanList);

            status = camessage ( prsrv_cast_client );
            if(status == RSRV_OK){
                if(prsrv_cast_client->recv.cnt != 
                    prsrv_cast_client->recv.stk){
                    char buf[40];
        
                    ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));

                    epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n",
                        prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf);
                }
            }
            else {
                char buf[40];
    
                ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf));

                epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf);
            }

            if (CASDEBUG>2) {
                if ( ellCount (&prsrv_cast_client->chanList) ) {
                    errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n",
                        ellCount(&prsrv_cast_client->chanList)-count,
                        ellCount(&prsrv_cast_client->chanList));
                }
            }
        }

        /*
         * allow messages to batch up if more are comming
         */
        nchars = 0; /* supress purify warning */
        status = socket_ioctl(IOC_cast_sock, FIONREAD, &nchars);
        if (status<0) {
            errlogPrintf ("CA cast server: Unable to fetch N characters pending\n");
            cas_send_dg_msg (prsrv_cast_client);
            clean_addrq ();
        }
        else if (nchars == 0) {
            cas_send_dg_msg (prsrv_cast_client);
            clean_addrq ();
        }
    }
}