示例#1
0
/*
 * makeSocket()
 */
static bool makeSocket ( unsigned short port, bool reuseAddr, SOCKET * pSock )
{
    int status;
	union {
		struct sockaddr_in ia;
		struct sockaddr sa;
	} bd;

    SOCKET sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, 0 );     
    if ( sock == INVALID_SOCKET ) {
        return false;
    }

    /*
     * no need to bind if unconstrained
     */
    if ( port != PORT_ANY ) {

        memset ( (char *) &bd, 0, sizeof (bd) );
        bd.ia.sin_family = AF_INET;
        bd.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); 
        bd.ia.sin_port = htons ( port );  
        status = bind ( sock, &bd.sa, (int) sizeof(bd) );
        if ( status < 0 ) {
            epicsSocketDestroy ( sock );
            return false;
        }
        if ( reuseAddr ) {
            epicsSocketEnableAddressReuseDuringTimeWaitState ( sock );
        }
    }
    *pSock = sock;
    return true;
}
示例#2
0
/*
 *
 * main()
 *
 */
int main(void)
{
    struct sockaddr_in serverAddr;  /* server's address */
    struct timeval timeout;
    int status;
    struct ioc_log_server *pserver;

    osiSockIoctl_t  optval;

    status = getConfig();
    if (status<0) {
        fprintf(stderr, "iocLogServer: EPICS environment underspecified\n");
        fprintf(stderr, "iocLogServer: failed to initialize\n");
        return IOCLS_ERROR;
    }

    pserver = (struct ioc_log_server *) 
            calloc(1, sizeof *pserver);
    if (!pserver) {
        fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
        return IOCLS_ERROR;
    }

    pserver->pfdctx = (void *) fdmgr_init();
    if (!pserver->pfdctx) {
        fprintf(stderr, "iocLogServer: %s\n", strerror(errno));
        return IOCLS_ERROR;
    }

    /*
     * Open the socket. Use ARPA Internet address format and stream
     * sockets. Format described in <sys/socket.h>.
     */
    pserver->sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0);
    if (pserver->sock == INVALID_SOCKET) {
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
        fprintf(stderr, "iocLogServer: sock create err: %s\n", sockErrBuf);
        free(pserver);
        return IOCLS_ERROR;
    }
    
    epicsSocketEnableAddressReuseDuringTimeWaitState ( pserver->sock );

    /* Zero the sock_addr structure */
    memset((void *)&serverAddr, 0, sizeof serverAddr);
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(ioc_log_port);

    /* get server's Internet address */
    status = bind ( pserver->sock, 
            (struct sockaddr *)&serverAddr, 
            sizeof (serverAddr) );
    if (status < 0) {
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
        fprintf(stderr, "iocLogServer: bind err: %s\n", sockErrBuf );
        fprintf (stderr,
            "iocLogServer: a server is already installed on port %u?\n", 
            (unsigned)ioc_log_port);
        return IOCLS_ERROR;
    }

    /* listen and accept new connections */
    status = listen(pserver->sock, 10);
    if (status < 0) {
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
        fprintf(stderr, "iocLogServer: listen err %s\n", sockErrBuf);
        return IOCLS_ERROR;
    }

    /*
     * Set non blocking IO
     * to prevent dead locks
     */
    optval = TRUE;
    status = socket_ioctl(
                    pserver->sock,
                    FIONBIO,
                    &optval);
    if (status < 0){
        char sockErrBuf[64];
        epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
        fprintf(stderr, "iocLogServer: ioctl FIONBIO err %s\n", sockErrBuf);
        return IOCLS_ERROR;
    }

#   ifdef UNIX
        status = setupSIGHUP(pserver);
        if (status < 0) {
            return IOCLS_ERROR;
        }
#   endif

    status = openLogFile(pserver);
    if (status < 0) {
        fprintf(stderr,
            "File access problems to `%s' because `%s'\n", 
            ioc_log_file_name,
            strerror(errno));
        return IOCLS_ERROR;
    }

    status = fdmgr_add_callback(
            pserver->pfdctx, 
            pserver->sock, 
            fdi_read,
            acceptNewClient,
            pserver);
    if (status < 0) {
        fprintf(stderr,
            "iocLogServer: failed to add read callback\n");
        return IOCLS_ERROR;
    }


    while (TRUE) {
        timeout.tv_sec = 60; /* 1 min */
        timeout.tv_usec = 0;
        fdmgr_pend_event(pserver->pfdctx, &timeout);
        fflush(pserver->poutfile);
    }
}
示例#3
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;
            }
        }
    }
}
示例#4
0
/*
 *  caStartRepeaterIfNotInstalled ()
 *
 *  Test for the repeater already installed
 *
 *  NOTE: potential race condition here can result
 *  in two copies of the repeater being spawned
 *  however the repeater detects this, prints a message,
 *  and lets the other task start the repeater.
 *
 *  QUESTION: is there a better way to test for a port in use? 
 *  ANSWER: none that I can find.
 *
 *  Problems with checking for the repeater installed
 *  by attempting to bind a socket to its address
 *  and port.
 *
 *  1) Closed socket may not release the bound port
 *  before the repeater wakes up and tries to grab it.
 *  Attempting to bind the open socket to another port
 *  also does not work.
 *
 *  072392 - problem solved by using SO_REUSEADDR
 */
void epicsShareAPI caStartRepeaterIfNotInstalled ( unsigned repeaterPort )
{
    bool installed = false;
    int status;
    SOCKET tmpSock;
    union {
        struct sockaddr_in ia; 
        struct sockaddr sa;
    } bd;

    if ( repeaterPort > 0xffff ) {
        fprintf ( stderr, "caStartRepeaterIfNotInstalled () : strange repeater port specified\n" );
        return;
    }

    tmpSock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
    if ( tmpSock != INVALID_SOCKET ) {
        ca_uint16_t port = static_cast < ca_uint16_t > ( repeaterPort );
        memset ( (char *) &bd, 0, sizeof ( bd ) );
        bd.ia.sin_family = AF_INET;
        bd.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); 
        bd.ia.sin_port = htons ( port );   
        status = bind ( tmpSock, &bd.sa, sizeof ( bd ) );
        if ( status < 0 ) {
            if ( SOCKERRNO == SOCK_EADDRINUSE ) {
                installed = true;
            }
            else {
                fprintf ( stderr, "caStartRepeaterIfNotInstalled () : bind failed\n" );
            }
        }
    }

    /*
     * turn on reuse only after the test so that
     * this works on kernels that support multicast
     */
    epicsSocketEnableAddressReuseDuringTimeWaitState ( tmpSock );

    epicsSocketDestroy ( tmpSock );

    if ( ! installed ) {
        
	    /*
	     * This is not called if the repeater is known to be 
	     * already running. (in the event of a race condition 
	     * the 2nd repeater exits when unable to attach to the 
	     * repeater's port)
	     */
		
		/* 
		 * look for a caRepeater in the same directory as CA.DLL 
		 * and use this if present instead of a PATH search
		 */
		char carep_path[256];
		strcpy(carep_path, "caRepeater");
#ifdef _WIN32		
		char caDLLPath[MAX_PATH];
		HMODULE hmod = GetModuleHandle("CA.DLL");
		if (hmod != NULL) {
		   if (GetModuleFileName(hmod, caDLLPath, sizeof(caDLLPath)) > 0) {
		       char* base_path = strrchr(caDLLPath, '\\');
			   if (base_path != NULL) {
			       *base_path = '\0';   // caDLLPath is now the directory containing CA.DLL
				   _snprintf(carep_path, sizeof(carep_path), "%s\\caRepeater.exe", caDLLPath);
					if (access(carep_path, 04) != 0) {
					    strcpy(carep_path, "caRepeater");  // Not found, so will search PATH instead for caRepeater
					}
			   }
		   }
		}
#endif /* _WIN32 */
		   
        osiSpawnDetachedProcessReturn osptr = 
            osiSpawnDetachedProcess ( "CA Repeater", carep_path );
        if ( osptr == osiSpawnDetachedProcessNoSupport ) {
            epicsThreadId tid;

            tid = epicsThreadCreate ( "CAC-repeater", epicsThreadPriorityLow,
                    epicsThreadGetStackSize ( epicsThreadStackMedium ), caRepeaterThread, 0);
            if ( tid == 0 ) {
                fprintf ( stderr, "caStartRepeaterIfNotInstalled : unable to create CA repeater daemon thread\n" );
            }
        }
        else if ( osptr == osiSpawnDetachedProcessFail ) {
            fprintf ( stderr, "caStartRepeaterIfNotInstalled (): unable to start CA repeater daemon detached process\n" );
        }
    }
}