void epicsAssert (const char *pFile, const unsigned line,
    const char *pExp, const char *pAuthorName)
{
    epicsTimeStamp current;

    errlogPrintf("\n\n\n"
        "A call to 'assert(%s)'\n"
        "    by thread '%s' failed in %s line %u.\n",
        pExp, epicsThreadGetNameSelf(), pFile, line);
    errlogPrintf("EPICS Release %s.\n", epicsReleaseVersion);

    if (epicsTimeGetCurrent(&current) == 0) {
        char date[64];

        epicsTimeToStrftime(date, sizeof(date),
            "%Y-%m-%d %H:%M:%S.%f %Z", &current);
        errlogPrintf("Local time is %s\n", date);
    }

    if (!pAuthorName) {
        pAuthorName = "the author";
    }
    errlogPrintf("Please E-mail this message to %s or to [email protected]\n",
        pAuthorName);

    errlogPrintf("Calling epicsThreadSuspendSelf()\n");
    epicsThreadSuspendSelf ();
}
Beispiel #2
0
static union twdNode *allocNode(void)
{
    union twdNode *pn = newNode();
    while (!pn) {
        errlogPrintf("Thread taskwd suspending: out of memory\n");
        epicsThreadSuspendSelf();
        pn = newNode();
    }
    return pn;
}
Beispiel #3
0
void testTask2(void *arg)
{
    taskwdInsert(0, taskNotify, NULL);
    testDiag("Task suspending");
    epicsThreadSuspendSelf();
    epicsThreadSleep(1.0);
    testDiag("Alive again");
    epicsThreadSleep(10.0);
    taskwdRemove(0);
}
Beispiel #4
0
static void msgbufFreeSend(void)
{
    msgNode *pnextSend;

    epicsMutexMustLock(pvtData.msgQueueLock);
    pnextSend = (msgNode *)ellFirst(&pvtData.msgQueue);
    if (!pnextSend) {
        fprintf(pvtData.console, "errlog: msgbufFreeSend logic error\n");
        epicsThreadSuspendSelf();
    }
    ellDelete(&pvtData.msgQueue, &pnextSend->node);
    epicsMutexUnlock(pvtData.msgQueueLock);
}
Beispiel #5
0
epicsShareFunc void * mallocMustSucceed(size_t size, const char *msg)
{
    void * mem = NULL;
    if (size > 0) {
        while ((mem = malloc(size)) == NULL) {
            errlogPrintf("%s: mallocMustSucceed(%lu) - malloc failed\n",
                msg, (unsigned long)size);
            errlogPrintf("Thread %s (%p) suspending.\n",
                    epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf());
            errlogFlush();
            epicsThreadSuspendSelf();
        }
    }
    return mem;
}
Beispiel #6
0
epicsShareFunc void cantProceed(const char *msg, ...)
{
    va_list pvar;
    va_start(pvar, msg);
    if (msg)
        errlogVprintf(msg, pvar);
    va_end(pvar);
    
    errlogPrintf("Thread %s (%p) can't proceed, suspending.\n",
            epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf());
    errlogFlush();
    
    epicsThreadSleep(1.0);
    while (1)
        epicsThreadSuspendSelf();
}
Beispiel #7
0
/*
 *
 *  req_server()
 *
 *  CA server task
 *
 *  Waits for connections at the CA port and spawns a task to
 *  handle each of them
 *
 */
static void req_server (void *pParm)
{
    unsigned priorityOfSelf = epicsThreadGetPrioritySelf ();
    unsigned priorityOfBeacons;
    epicsThreadBooleanStatus tbs;
    struct sockaddr_in serverAddr;  /* server's address */
    osiSocklen_t addrSize;
    int status;
    SOCKET clientSock;
    epicsThreadId tid;
    int portChange;

    epicsSignalInstallSigPipeIgnore ();

    taskwdInsert ( epicsThreadGetIdSelf (), NULL, NULL );
    
    rsrvCurrentClient = epicsThreadPrivateCreate ();

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

    if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) {
        epicsSocketDestroy ( IOC_sock );
    }
    
    /*
     * Open the socket. Use ARPA Internet address format and stream
     * sockets. Format described in <sys/socket.h>.
     */
    if ( ( IOC_sock = epicsSocketCreate (AF_INET, SOCK_STREAM, 0) ) == INVALID_SOCKET ) {
        errlogPrintf ("CAS: Socket creation error\n");
        epicsThreadSuspendSelf ();
    }

    epicsSocketEnableAddressReuseDuringTimeWaitState ( IOC_sock );

    /* Zero the sock_addr structure */
    memset ( (void *) &serverAddr, 0, sizeof ( serverAddr ) );
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl (INADDR_ANY); 
    serverAddr.sin_port = htons ( ca_server_port );

    /* get server's Internet address */
    status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
	if ( status < 0 ) {
		if ( SOCKERRNO == SOCK_EADDRINUSE ) {
			/*
			 * enable assignment of a default port
			 * (so the getsockname() call below will
			 * work correctly)
			 */
			serverAddr.sin_port = ntohs (0);
			status = bind ( IOC_sock, 
                (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
		}
		if ( status < 0 ) {
            char sockErrBuf[64];
            epicsSocketConvertErrnoToString ( 
                sockErrBuf, sizeof ( sockErrBuf ) );
            errlogPrintf ( "CAS: Socket bind error was \"%s\"\n",
                sockErrBuf );
            epicsThreadSuspendSelf ();
		}
        portChange = 1;
	}
    else {
        portChange = 0;
    }

	addrSize = ( osiSocklen_t ) sizeof ( serverAddr );
	status = getsockname ( IOC_sock, 
			(struct sockaddr *)&serverAddr, &addrSize);
	if ( status ) {
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( 
            sockErrBuf, sizeof ( sockErrBuf ) );
		errlogPrintf ( "CAS: getsockname() error %s\n", 
			sockErrBuf );
        epicsThreadSuspendSelf ();
	}

    ca_server_port = ntohs (serverAddr.sin_port);

    if ( portChange ) {
        errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
        errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n", 
            ca_server_port );
        errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
        errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
        errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
    }

    /* listen and accept new connections */
    if ( listen ( IOC_sock, 20 ) < 0 ) {
        errlogPrintf ("CAS: Listen error\n");
        epicsSocketDestroy (IOC_sock);
        epicsThreadSuspendSelf ();
    }

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

    beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
    beacon_ctl = ctlPause;

    tid = epicsThreadCreate ( "CAS-beacon", priorityOfBeacons,
        epicsThreadGetStackSize (epicsThreadStackSmall),
        rsrv_online_notify_task, 0 );
    if ( tid == 0 ) {
        epicsPrintf ( "CAS: unable to start beacon thread\n" );
    }

    epicsEventMustWait(beacon_startStopEvent);
    epicsEventSignal(castcp_startStopEvent);

    while (TRUE) {
        struct sockaddr     sockAddr;
        osiSocklen_t        addLen = sizeof(sockAddr);

        while (castcp_ctl == ctlPause) {
            epicsThreadSleep(0.1);
        }

        clientSock = epicsSocketAccept ( IOC_sock, &sockAddr, &addLen );
        if ( clientSock == INVALID_SOCKET ) {
            char sockErrBuf[64];
            epicsSocketConvertErrnoToString ( 
                sockErrBuf, sizeof ( sockErrBuf ) );
            errlogPrintf("CAS: Client accept error was \"%s\"\n",
                sockErrBuf );
            epicsThreadSleep(15.0);
            continue;
        } 
        else {
            epicsThreadId id;
            struct client *pClient;

            /* socket passed in is closed if unsuccessful here */
            pClient = create_tcp_client ( clientSock );
            if ( ! pClient ) {
                epicsThreadSleep ( 15.0 );
                continue;
            }

            LOCK_CLIENTQ;
            ellAdd ( &clientQ, &pClient->node );
            UNLOCK_CLIENTQ;

            id = epicsThreadCreate ( "CAS-client", epicsThreadPriorityCAServerLow,
                    epicsThreadGetStackSize ( epicsThreadStackBig ),
                    camsgtask, pClient );
            if ( id == 0 ) {
                LOCK_CLIENTQ;
                ellDelete ( &clientQ, &pClient->node );
                UNLOCK_CLIENTQ;
                destroy_tcp_client ( pClient );
                errlogPrintf ( "CAS: task creation for new client failed\n" );
                epicsThreadSleep ( 15.0 );
                continue;
            }
        }
    }
}
Beispiel #8
0
/*
 * Process breakpoint
 *  Returns a zero if dbProcess() is to execute
 *  record support, a one if dbProcess() is to
 *  skip over record support.  See dbProcess().
 *
 *  1.  See if there is at least a breakpoint set somewhere
 *        in precord's lockset.  If not, return immediately.
 *  2.  Check the disable flag.
 *  3.  Add entry points to the queue for future stepping and
 *        schedule new entrypoints for the continuation task.
 *  4.  Check the pact flag.
 *  5.  Check to see if there is a breakpoint set in a record, and
 *        if so, turn on stepping mode.
 *  6.  If stepping mode is set, stop and report the breakpoint.
 */
int epicsShareAPI dbBkpt(dbCommon *precord)
{
  struct LS_LIST *pnode;
  struct EP_LIST *pqe;

 /*
  *  It is crucial that operations in dbBkpt() execute
  *    in the correct order or certain features in the
  *    breakpoint handler will not work as expected.
  */

 /*
  *  Take and give a semaphore to check for breakpoints
  *	every time a record is processed.  Slow.  Thank
  *	goodness breakpoint checking is turned off during
  *	normal operation.
  */
  epicsMutexMustLock(bkpt_stack_sem);
  FIND_LOCKSET(precord, pnode);
  epicsMutexUnlock(bkpt_stack_sem);

  if (pnode == NULL) {
    /* no breakpoints in precord's lockset */
     return(0);
  }

 /* Check disable flag */
  dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0);
  if (precord->disa == precord->disv) {
     /*
      *  Do not process breakpoints if the record is disabled,
      *    but allow disable alarms.  Alarms will be raised
      *    in dbProcess() because returning 0 allows dbProcess()
      *    to continue.  However processing will be prevented
      *    because disa and disv will be examined again in
      *    dbProcess(). Note that checking for pact will occur
      *    before checking for disa and disv in dbProcess().
      */
      return(0);
  }

 /*
  *  Queue entry points for future stepping.  The taskid comparison
  *    is used to determine if the source of processing is the
  *    continuation task or an external source. If it is an external
  *    source, queue its execution, but dump out of dbProcess without
  *    calling record support. 
  */
  if (pnode->taskid && (epicsThreadGetIdSelf() != pnode->taskid)) {
    /* CONTINUE TASK CANNOT ENTER HERE */

    /*
     *  Add an entry point to queue, if it does
     *    not already exist.
     */
     FIND_QUEUE_ENTRY(&pnode->ep_queue, pqe, precord);
 
     if (pqe == NULL) {

        pqe = (struct EP_LIST *) malloc(sizeof(struct EP_LIST));
        if (pqe == NULL)
             return(1);


        pqe->entrypoint = precord;
        pqe->count = 1;
        epicsTimeGetCurrent(&pqe->time);
        pqe->sched = 0;

#ifdef BKPT_DIAG
        printf("   BKPT> Adding entrypoint %s to queue\n", precord->name);
#endif

       /*
        *  Take semaphore, wait on continuation task
        */
        epicsMutexMustLock(bkpt_stack_sem);

       /* Add entry to queue */
        ellAdd(&pnode->ep_queue, (ELLNODE *)pqe);

        epicsMutexUnlock(bkpt_stack_sem);
     }
     else {
        if (pqe->count < MAX_EP_COUNT)
           pqe->count++;
     }

    /* check pact */
     if (! precord->pact) {
       /* schedule if pact not set */
        pqe->sched = 1;

       /*
        *  Release the semaphore, letting the continuation
        *     task begin execution of the new entrypoint.
        */ 
        epicsEventSignal(pnode->ex_sem);
     }
     return(1);
  }

 /*
  *  Don't mess with breakpoints if pact set!  Skip
  *    over rest of dbProcess() since we don't want
  *    alarms going off.  The pact flag is checked
  *    AFTER entry point queuing so that the record
  *    timing feature will work properly.
  */
  if (precord->pact)
     return(1);

 /* Turn on stepping mode if a breakpoint is found */
  if (precord->bkpt & BKPT_ON_MASK) {
     pnode->step = 1;

#ifdef BKPT_DIAG
     printf("   BKPT> Bkpt detected: %s\n", precord->name);
#endif
  }

 /*
  *  If we are currently stepping through the lockset,
  *    suspend task.
  */
  if (pnode->step) {
      printf("\n   BKPT> Stopped at:  %s  within Entrypoint:  %s\n-> ",
                 precord->name, pnode->current_ep->name);

      pnode->precord = precord;

     /* Move current lockset to top of stack */
      ellDelete(&lset_stack, (ELLNODE *)pnode);
      ellInsert(&lset_stack, NULL, (ELLNODE *)pnode);
     /*
      *  Unlock database while the task suspends itself.  This
      *   is done so that dbb() dbd() dbc() dbs() may be used
      *   when the task is suspended.  Scan tasks that also
      *   use the scan lock feature will not be hung during
      *   a breakpoint, so that records in other locksets will
      *   continue to be processed.  Cross your fingers, this
      *   might actually work !
      */
      epicsMutexUnlock(bkpt_stack_sem);
      dbScanUnlock(precord);
      epicsThreadSuspendSelf();
      dbScanLock(precord);
      epicsMutexMustLock(bkpt_stack_sem);
   }
   return(0);
}
Beispiel #9
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 */
        }
    }
}
Beispiel #10
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 ();
        }
    }
}