コード例 #1
0
ANSC_STATUS
AnscDsuoAcceptTask
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SERVER_UDP_OBJECT  pMyObject     = (PANSC_DAEMON_SERVER_UDP_OBJECT)hThisObject;
    PANSC_DSUO_WORKER_OBJECT        pWorker       = (PANSC_DSUO_WORKER_OBJECT      )pMyObject->hWorker;
    PANSC_DAEMON_ENGINE_UDP_OBJECT  pCurEngine    = NULL;
    PANSC_DSUO_PACKET_OBJECT        pNewPacket    = NULL;
    int                             s_result      = 0;
    int                             s_error       = 0;
    char*                           recv_buffer   = NULL;
    int                             recv_size     = 0;
    ansc_fd_set                     read_fd_set;
    xskt_fd_set                     read_fd_set2;
    ansc_timeval                    timeval;
    xskt_timeval                    timeval2;
    ansc_socket_addr_in             client_addr;
    xskt_socket_addr_in             client_addr2;
    int                             addrlen;

    AnscTrace("AnscDsuoAcceptTask is activated ...!\n");

    /*
     * As a scalable server implemention, we shall accept as many incoming client connections as
     * possible and can only be limited by the system resources. Once the listening socket becomes
     * readable, which means an incoming connection attempt has arrived. We create a new socket
     * object and associate it with the client. This is a repeated process until the socket owner
     * closes the socket.
     */
    while ( pMyObject->bActive )
    {
        ANSC_COMMIT_TASK();
        
        /*
         * Since the original bsd compatible socket api doesn't support asynchronous operation, the
         * nonblocking status polling is the best we can get. As a matter of fact, the current unix
         * and linux actually still don't support asynchronous notification on any socket operation.
         */

        /*
         * Since only one socket is included in the fd_set, we only distinguish the result between
         * one and non-one values. If error is detected, we shall close the socket and notify the
         * socket owner immediately.
         */
        if ( pMyObject->Mode & ANSC_DSUO_MODE_XSOCKET )
        {
            XSKT_SOCKET_FD_ZERO(&read_fd_set2);
            XSKT_SOCKET_FD_SET ((XSKT_SOCKET)pMyObject->Socket, &read_fd_set2);
            timeval2.tv_sec  = (ANSC_DSUO_POLL_INTERVAL_MS / 1000);          /* number of seconds      */
            timeval2.tv_usec = (ANSC_DSUO_POLL_INTERVAL_MS % 1000) * 1000;   /* number of microseconds */

            s_result = _xskt_select(pMyObject->Socket + 1, &read_fd_set2, NULL, NULL, &timeval2);
        }
        else
        {
            ANSC_SOCKET_FD_ZERO(&read_fd_set);
            ANSC_SOCKET_FD_SET (pMyObject->Socket, &read_fd_set);
            timeval.tv_sec  = (ANSC_DSUO_POLL_INTERVAL_MS / 1000);          /* number of seconds      */
            timeval.tv_usec = (ANSC_DSUO_POLL_INTERVAL_MS % 1000) * 1000;   /* number of microseconds */

            s_result = _ansc_select(pMyObject->Socket + 1, &read_fd_set, NULL, NULL, &timeval);
        }

        if ( s_result == 0 )
        {
            continue;
        }
        else if ( s_result == ANSC_SOCKET_ERROR )
        {
            s_error = _ansc_get_last_error();

            continue;
        }

        /*
         * According to de facto standards of bsd compatible socket api, if the socket is currently
         * in the listen state, it will be marked as readable if an incoming connection request has
         * been received such that an accept is guaranteed to complete without blocking.
         */

        pNewPacket =
            (PANSC_DSUO_PACKET_OBJECT)pMyObject->AcquirePacket
                (
                    (ANSC_HANDLE)pMyObject
                );

        if ( !pNewPacket )
        {
            continue;
        }
        else
        {
            recv_buffer = pNewPacket->RecvBuffer;
            recv_size   = pNewPacket->RecvBufferSize;
        }

        if ( pMyObject->Mode & ANSC_DSUO_MODE_XSOCKET )
        {
            client_addr2.sin_family                                 = ANSC_SOCKET_AF_INET;
            ((pansc_socket_addr_in)&client_addr2)->sin_addr.s_addr  = 0;
            client_addr2.sin_port                                   = _xskt_htons(pMyObject->HostPort);
            addrlen                                                 = sizeof(client_addr2);
            s_result = _xskt_recvfrom(pMyObject->Socket, recv_buffer, recv_size, 0, (xskt_socket_addr*)&client_addr2, &addrlen);
        }
        else
        {
            client_addr.sin_family      = ANSC_SOCKET_AF_INET;
            client_addr.sin_addr.s_addr = 0;
            client_addr.sin_port        = _ansc_htons(pMyObject->HostPort);
            addrlen                     = sizeof(client_addr);
            s_result = _ansc_recvfrom(pMyObject->Socket, recv_buffer, recv_size, 0, (ansc_socket_addr*)&client_addr, &addrlen);
        }

        if ( s_result == ANSC_SOCKET_ERROR )
        {
            s_error = _ansc_get_last_error();

            returnStatus =
                pMyObject->ReleasePacket
                    (
                        (ANSC_HANDLE)pMyObject,
                        (ANSC_HANDLE)pNewPacket
                    );

            continue;
        }
        else if ( !pMyObject->bActive )
        {
            returnStatus =
                pMyObject->ReleasePacket
                    (
                        (ANSC_HANDLE)pMyObject,
                        (ANSC_HANDLE)pNewPacket
                    );

            break;
        }
        else
        {
            recv_size = s_result;
        }

        if ( pMyObject->Mode & ANSC_DSUO_MODE_XSOCKET )
        {
            pNewPacket->PeerAddress.Value = ((pansc_socket_addr_in)&client_addr2)->sin_addr.s_addr;
            pNewPacket->PeerPort          = _ansc_ntohs(client_addr2.sin_port);
        }
        else
        {
            pNewPacket->PeerPort          = _ansc_ntohs(client_addr.sin_port);
            pNewPacket->PeerAddress.Value = client_addr.sin_addr.s_addr;
        }
        pNewPacket->RecvPacketSize    = (ULONG)recv_size;
        pNewPacket->RecvAt            = AnscGetTickInSeconds();

        /*
         * We have to assign an engine object to this new packet object. The assignment is done by
         * address-hashing. However, we need to make sure that the assigned engine object is not
         * over-loaded. If it is, there're nothing we can do except throwing the packet away.
         */
        pCurEngine =
            (PANSC_DAEMON_ENGINE_UDP_OBJECT)pMyObject->AssignEngine
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pNewPacket
                );

        if ( !pCurEngine )
        {
            returnStatus =
                pMyObject->ReleasePacket
                    (
                        (ANSC_HANDLE)pMyObject,
                        (ANSC_HANDLE)pNewPacket
                    );

            continue;
        }
        else
        {
            returnStatus =
                pCurEngine->AddPacket
                    (
                        (ANSC_HANDLE)pCurEngine,
                        (ANSC_HANDLE)pNewPacket
                    );
        }

        if ( returnStatus != ANSC_STATUS_SUCCESS )
        {
            returnStatus =
                pMyObject->ReleasePacket
                    (
                        (ANSC_HANDLE)pMyObject,
                        (ANSC_HANDLE)pNewPacket
                    );
        }
    }

    AnscSetEvent(&pMyObject->AcceptEvent);

    return  ANSC_STATUS_SUCCESS;
}
コード例 #2
0
ANSC_STATUS
AnscDstoEngage
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pMyObject->hWorker;
    int                             s_result     = 0;
#ifdef _ANSC_IPV6_COMPATIBLE_
    ansc_addrinfo                   ansc_hints           = {0};
    ansc_addrinfo*                  pansc_local_addrinfo = NULL;
    xskt_addrinfo                   xskt_hints           = {0};
    xskt_addrinfo*                  pxskt_local_addrinfo = NULL;
    USHORT                          usPort               = 0;
    char                            port[6]              = {0};
#else
    /*RDKB-6151, CID-24487,24794; initializing variable before use*/
    ansc_socket_addr_in             local_addr1 = {0};
    xskt_socket_addr_in             local_addr2 = {0};
#endif

    if ( pMyObject->bActive )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    else if ( !pWorker )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        pWorker->Init(pWorker->hWorkerContext);

        pMyObject->StartTime = AnscGetTickInSecondsAbs();
        pMyObject->bActive   = TRUE;
    }

    /*
     * The underlying socket wrapper may require an explicit startup() call, such is the case on
     * Microsoft windows platforms. The wrapper initialization has to done for each task. On most
     * real-time operating systems, this call is not required.
     */
    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        AnscStartupXsocketWrapper((ANSC_HANDLE)pMyObject);
    }
    else
    {
        AnscStartupSocketWrapper((ANSC_HANDLE)pMyObject);
    }
    
#ifdef _ANSC_IPV6_COMPATIBLE_

    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        xskt_hints.ai_family   = AF_UNSPEC;
        xskt_hints.ai_socktype = XSKT_SOCKET_STREAM;
        xskt_hints.ai_flags    = AI_PASSIVE | AI_ADDRCONFIG;

        usPort = pMyObject->GetHostPort((ANSC_HANDLE)pMyObject);
        _ansc_sprintf(port, "%d", usPort);
        CcspTraceInfo(("!!! Host Name: %s, Host Port: %s !!!\n", pMyObject->HostName, port));

        if ( _xskt_getaddrinfo
                (
                    pMyObject->HostName[0] ? pMyObject->HostName : "::", 
                    port,
                    &xskt_hints,
                    &pxskt_local_addrinfo
                ) 
            )
        {
            CcspTraceError(("!!! error 1 !!!\n"));

            returnStatus = ANSC_STATUS_FAILURE;
            
            goto  EXIT1;
        }
        
        pMyObject->pHostAddr2 = pxskt_local_addrinfo;
    }
    else
    {
        ansc_hints.ai_family   = AF_UNSPEC;
        ansc_hints.ai_socktype = ANSC_SOCKET_STREAM;
        ansc_hints.ai_flags    = AI_PASSIVE | AI_ADDRCONFIG;

        usPort = pMyObject->GetHostPort((ANSC_HANDLE)pMyObject);
        _ansc_sprintf(port, "%d", usPort);
        CcspTraceInfo(("!!! Host Name: %s, Host Port: %s !!!\n", pMyObject->HostName, port));

        if ( _ansc_getaddrinfo
                (
                    pMyObject->HostName[0] ? pMyObject->HostName : "::",
                    port,
                    &ansc_hints,
                    &pansc_local_addrinfo
                ) 
            )
        {
            returnStatus = ANSC_STATUS_FAILURE;

            goto  EXIT1;
        }
        
        pMyObject->pHostAddr1 = pansc_local_addrinfo;
    }

#endif

    /*
     * To engage the Tcp Daemon, we need to perform following acts in the respective order:
     *
     *      (1) create the os-dependent socket
     *      (2) manufacture and start all the engines objects
     *      (3) manufacture the global socket object pool
     *      (4) bind to the socket and listen on it
     */
    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
#ifdef _ANSC_IPV6_COMPATIBLE_
        pMyObject->Socket = _xskt_socket(pxskt_local_addrinfo->ai_family, pxskt_local_addrinfo->ai_socktype, 0);
#else
        pMyObject->Socket = _xskt_socket(XSKT_SOCKET_AF_INET, XSKT_SOCKET_STREAM, 0);
#endif
    }
    else
    {
#ifdef _ANSC_IPV6_COMPATIBLE_
        pMyObject->Socket = _ansc_socket(pansc_local_addrinfo->ai_family, pansc_local_addrinfo->ai_socktype, 0);
#else
        pMyObject->Socket = _ansc_socket(ANSC_SOCKET_AF_INET, ANSC_SOCKET_STREAM, 0);
#endif
    }

    if ( ((pMyObject->Socket == XSKT_SOCKET_INVALID_SOCKET) &&  (pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) ||
         ((pMyObject->Socket == ANSC_SOCKET_INVALID_SOCKET) && !(pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) )
    {
        returnStatus = ANSC_STATUS_FAILURE;

        goto  EXIT1;
    }

    _ansc_en_reuseaddr(pMyObject->Socket);

#ifndef _ANSC_IPV6_COMPATIBLE_
    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        local_addr2.sin_family = XSKT_SOCKET_AF_INET;
        local_addr2.sin_port   = _xskt_htons(pMyObject->HostPort);

        if ( pMyObject->HostAddress.Value == 0 )
        {
            ((pansc_socket_addr_in)&local_addr2)->sin_addr.s_addr = XSKT_SOCKET_ANY_ADDRESS;
        }
        else
        {
            ((pansc_socket_addr_in)&local_addr2)->sin_addr.s_addr = pMyObject->HostAddress.Value;
        }
    }
    else
    {
        local_addr1.sin_family = ANSC_SOCKET_AF_INET;
        local_addr1.sin_port   = _ansc_htons(pMyObject->HostPort);

        if ( pMyObject->HostAddress.Value == 0 )
        {
            local_addr1.sin_addr.s_addr = ANSC_SOCKET_ANY_ADDRESS;
        }
        else
        {
            local_addr1.sin_addr.s_addr = pMyObject->HostAddress.Value;
        }
    }
#endif

#if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX)
    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
#ifdef _ANSC_IPV6_COMPATIBLE_
        s_result = _xskt_bind(pMyObject->Socket, pxskt_local_addrinfo->ai_addr, pxskt_local_addrinfo->ai_addrlen);
#else
        AnscTrace("AnscDstoEngage -- the address is 0x%lX:%d, familty %d.\n", _ansc_ntohl(local_addr2.sin_addr.s_addr), _ansc_ntohs(local_addr2.sin_port), local_addr2.sin_family);
        s_result = _xskt_bind(pMyObject->Socket, (xskt_socket_addr*)&local_addr2, sizeof(local_addr2));
#endif
    }
    else
    {
#ifdef _ANSC_IPV6_COMPATIBLE_
        s_result = _ansc_bind(pMyObject->Socket, pansc_local_addrinfo->ai_addr, pansc_local_addrinfo->ai_addrlen);
#else
        s_result = _ansc_bind(pMyObject->Socket, (ansc_socket_addr*)&local_addr1, sizeof(local_addr1));
#endif
    }
#else
	if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        while ( _xskt_bind(pMyObject->Socket, (ansc_socket_addr*)&local_addr2, sizeof(local_addr2)) != 0 )
        {
            AnscTrace
				(
					"AnscDstoEngage -- failure to bind try again !socket %d family %d port %d address %X \n",
					pMyObject->Socket,
					local_addr2.sin_family,
                    local_addr2.sin_port,
					((pansc_socket_addr_in)&local_addr2)->sin_addr.s_addr
				);

            AnscSleep(10);
        }
    }
    else
    {
        while ( _ansc_bind(pMyObject->Socket, (ansc_socket_addr*)&local_addr1, sizeof(local_addr1)) != 0 )
        {
            AnscTrace
				(
					"AnscDstoEngage -- failure to bind try again !socket %d family %d port %d address %X \n",
					pMyObject->Socket,
					local_addr1.sin_family,
                    local_addr1.sin_port,
					local_addr1.sin_addr.s_addr
				);

            AnscSleep(10);
        }
    }
#endif

    if ( s_result != 0 )
    {
		AnscTrace
            (
                "AnscDstoEngage -- failed to bind to the socket, error code is %d!!!\n",
                (pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET) ? _xskt_get_last_error() : _ansc_get_last_error()
            );

        returnStatus = ANSC_STATUS_FAILURE;

        goto  EXIT2;
    }

    pMyObject->ManufactureEnginePool((ANSC_HANDLE)pMyObject);
    pMyObject->ManufactureSocketPool((ANSC_HANDLE)pMyObject);
    pMyObject->StartEngines         ((ANSC_HANDLE)pMyObject);

    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        s_result = _xskt_listen(pMyObject->Socket, ANSC_SOCKET_BACKLOG_VALUE);
    }
    else
    {
        s_result = _ansc_listen(pMyObject->Socket, ANSC_SOCKET_BACKLOG_VALUE);
    }

    if ( s_result != 0 )
    {
		AnscTrace("AnscDstoEngage -- failed to listen on the socket!\n");

        returnStatus = ANSC_STATUS_FAILURE;

        goto  EXIT2;
    }

    /*
     * If the compilation option '_ANSC_SOCKET_TLS_LAYER_' is enabled, we can simply let the ANSC
     * socket layer to perform the SSL/TLS functionality; otherwise, we need to prepare for doing
     * SSL/TLS internally.
     */
    if ( pMyObject->Mode & ANSC_DSTO_MODE_TLS_ENABLED )
    {
#ifdef _ANSC_USE_OPENSSL_
        pMyObject->bTlsEnabled = TRUE;
        if ( !openssl_init(SSL_SERVER_CALLS) )
        {
        	AnscTrace("AnscSctoEngage - openssl_init() failed!\n");
            returnStatus = ANSC_STATUS_FAILURE;
            goto  EXIT2;
        }

#else
        #ifdef  _ANSC_SOCKET_TLS_LAYER_
        {
            _ansc_en_usetls(pMyObject->Socket);

            pMyObject->bTlsEnabled = FALSE;
        }
        #else
        {
            pMyObject->hTlsScsIf   = (pMyObject->hTlsScsIf != NULL)? pMyObject->hTlsScsIf : AnscSocketTlsGetScsIf();
            pMyObject->bTlsEnabled = TRUE;
            pMyObject->bTlsReqCert = (pMyObject->Mode & ANSC_DSTO_MODE_TLS_REQ_CERT);
        }
        #endif
#endif
    }

    AnscResetEvent(&pMyObject->AcceptEvent);
    returnStatus =
        pMyObject->SpawnTask3
            (
                (ANSC_HANDLE)pMyObject,
                (void*      )pMyObject->AcceptTask,
                (ANSC_HANDLE)pMyObject,
                ANSC_DSTO_ACCEPT_TASK_NAME,
                USER_DEFAULT_TASK_PRIORITY,
                2*USER_DEFAULT_TASK_STACK_SIZE

            );

    return  ANSC_STATUS_SUCCESS;


    /******************************************************************
                GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS
    ******************************************************************/

EXIT2:

    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        _xskt_closesocket(pMyObject->Socket);
    }
    else
    {
        _ansc_closesocket(pMyObject->Socket);
    }

EXIT1:

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        pMyObject->bActive = FALSE;
    }

    return  returnStatus;
}