ANSC_STATUS
AnscDeuoStart
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_UDP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_UDP_OBJECT)hThisObject;

    if ( pMyObject->bStarted )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    else
    {
        pMyObject->bStarted = TRUE;
    }

    pMyObject->Reset((ANSC_HANDLE)pMyObject);

    if ( TRUE )
    {
        AnscResetEvent(&pMyObject->RecvEvent);
        returnStatus =
            AnscSpawnTask
                (
                    (void*)pMyObject->RecvTask,
                    (ANSC_HANDLE)pMyObject,
                    ANSC_DEUO_RECV_TASK_NAME
                );
    }

    if ( pMyObject->ControlFlags & ANSC_DEUO_FLAG_ASYNC_SEND )
    {
        AnscResetEvent(&pMyObject->SendEvent);
        returnStatus =
            AnscSpawnTask
                (
                    (void*)pMyObject->SendTask,
                    (ANSC_HANDLE)pMyObject,
                    ANSC_DEUO_SEND_TASK_NAME
                );
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDetoStart
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject;

    if ( pMyObject->bStarted )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    else
    {
        pMyObject->Reset((ANSC_HANDLE)pMyObject);

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

    if ( TRUE )
    {
        AnscResetEvent(&pMyObject->RecvEvent);
        returnStatus =
            AnscSpawnTask3
                (
                    (void*)pMyObject->RecvTask,
                    (ANSC_HANDLE)pMyObject,
                    ANSC_DETO_RECV_TASK_NAME,
                    ANSC_TASK_PRIORITY_NORMAL,
                    ANSC_DETO_RECV_TASK_STACK_SIZE
                );
    }

    if ( pMyObject->ControlFlags & ANSC_DETO_FLAG_ASYNC_SEND )
    {
        AnscResetEvent(&pMyObject->SendEvent);
        returnStatus =
            AnscSpawnTask
                (
                    (void*)pMyObject->SendTask,
                    (ANSC_HANDLE)pMyObject,
                    ANSC_DETO_SEND_TASK_NAME
                );
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
BbhmDownloadStartDiag
    (
        ANSC_HANDLE                 hThisObject
    )
{
    /* start the diagnostics */
    AnscSpawnTask
        (
            bbhmDownloadStartDiagTask,
            (ANSC_HANDLE)hThisObject,
            "bbhmDownloadStartDiagTask"
        );

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
CosaDmlDiagScheduleDiagnostic
    (
        ULONG                       ulDiagType,
        ANSC_HANDLE                 hDiagInfo
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_FAILURE;
    struct  AsyncDiagInfo  *        pInfo       = NULL;

    /*
    * you can replace this function calling with your
    * own real diagnostic process
    */

    if ( g_pCosaDiagPluginInfo )
    {
        if ( g_pCosaDiagPluginInfo->uLoadStatus != COSA_STATUS_SUCCESS )
        {
            AnscTraceWarning(("COSA Diagnostic library is not ready...\n"));

            return ANSC_STATUS_FAILURE;
        }

        pInfo = AnscAllocateMemory(sizeof(*pInfo));

        if (!pInfo)
            return ANSC_STATUS_FAILURE;

        pInfo->type      = ulDiagType;
        pInfo->hDiagInfo = hDiagInfo;
        
        AnscSpawnTask
            (
                (void *)_AsyncScheduleDiagnostic,
                (ANSC_HANDLE)pInfo,
                "AsyncSheduleDiagnostic"
            );
    }

    return returnStatus;
}
ANSC_STATUS
StunScoStageTimerInvoke
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus      = ANSC_STATUS_SUCCESS;
    PSTUN_SIMPLE_CLIENT_OBJECT      pMyObject         = (PSTUN_SIMPLE_CLIENT_OBJECT    )hThisObject;
    PSTUN_SIMPLE_CLIENT_PROPERTY    pProperty         = (PSTUN_SIMPLE_CLIENT_PROPERTY  )&pMyObject->Property;
    PANSC_TIMER_DESCRIPTOR_OBJECT   pProbeTimerObj    = (PANSC_TIMER_DESCRIPTOR_OBJECT )pMyObject->hProbeTimerObj;
    PANSC_SIMPLE_CLIENT_UDP_OBJECT  pSimpleClientUdp1 = (PANSC_SIMPLE_CLIENT_UDP_OBJECT)pMyObject->hSimpleClientUdp1;

    switch ( pMyObject->ClientStage )
    {
        case    STUN_SCO_CLIENT_STAGE_Discovering :

                /*
                 * So the stage timer finally fired. We have either succeeded or failed in
                 * acquiring a NAT binding. The simplest way of telling is to check whether the
                 * detected NAT-ed IP address is zero.
                 */
                if ( pMyObject->BindingInfo.Ip4Addr.Value == 0 )
                {
                    break;
                }
                else
                {
                    pMyObject->ClientStage = STUN_SCO_CLIENT_STAGE_Maintaining;

                    /*
                     * STUN can be used to discover the lifetimes of the bindings created by the
                     * NAT. In many cases, the client will need to refresh the binding, either
                     * through a new STUN request, or an application packet, in order for the
                     * application to continue to use the binding. By discovering the binding life-
                     * time, the client can determine how frequently it needs to refresh.
                     */
                    returnStatus =
                        AnscSpawnTask
                            (
                                pMyObject->AsyncDiscoverTask,
                                (ANSC_HANDLE)pMyObject,
                                "stun_discover_task"
                            );

                    /*
                     * Before the best keepalive interval is determined, we shall use the minimum
                     * interval to avoid being disconnected.
                     */
                    pProperty->CurKeepAliveInterval = pProperty->MinKeepAliveInterval;

                    pProbeTimerObj->SetInterval((ANSC_HANDLE)pProbeTimerObj, pProperty->CurKeepAliveInterval * 1000);
                    pProbeTimerObj->Start      ((ANSC_HANDLE)pProbeTimerObj);
                }

                break;

        default :

                break;
    }

    return  returnStatus;
}