/**
 * timerThread
 *
 * @brief Timer service thread
 *
 * This is the start function for the timer server thread.
 *
 * @param[in] data - The data passed in (UNUSED)
 *
 * @return  This function eventually starts an infinite loop on a "select".
 */
void *timerThread (void *data)
{
    static const char fname[] = "timerThread";

    //CPR_INFO("timerThread:started..\n");
#ifndef HOST
#ifndef PTHREAD_SET_NAME
#define PTHREAD_SET_NAME(s)     do { } while (0)
#endif
    PTHREAD_SET_NAME("CPR Timertask");
#endif

    /*
     * Increase the timer thread priority from default priority.
     * This is required to make sure timers fire with reasonable precision.
     *
     * NOTE: always make sure the priority is higher than sip/gsm threads;
     * otherwise, we must use mutex around the following while loop.
     */
    (void) cprAdjustRelativeThreadPriority(TIMER_THREAD_RELATIVE_PRIORITY);

    /* get ready to listen for timer commands and service them */
    if (start_timer_service_loop() == CPR_FAILURE) {
        CPR_ERROR("%s: timer service loop failed\n", fname);
    }

    return NULL;
}
Пример #2
0
/**
 *
 * sip_platform_task_loop
 *
 * Run the SIP task
 *
 * Parameters: arg - SIP message queue
 *
 * Return Value: None
 *
 */
void
sip_platform_task_loop (void *arg)
{
    static const char *fname = "sip_platform_task_loop";
    int pending_operations;
    uint16_t i;
    fd_set sip_read_fds;
    fd_set sip_write_fds;
    sip_tcp_conn_t *entry;

    sip_msgq = (cprMsgQueue_t) arg;
    if (!sip_msgq) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_msgq is null, exiting", fname);
        return;
    }
    sip.msgQueue = sip_msgq;

    sip_platform_task_init();
    /*
     * Initialize the SIP task
     */
    SIPTaskInit();

    if (platThreadInit("SIPStack Task") != 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to attach thread to JVM", fname);
        return;
    }

    /*
     * Adjust relative priority of SIP thread.
     */
    (void) cprAdjustRelativeThreadPriority(SIP_THREAD_RELATIVE_PRIORITY);

    /*
     * Setup IPC socket addresses for main thread (server)
     */
    {
      char stmpdir[sizeof(sip_serv_sock_addr.sun_path)];
      sip_get_sock_dir(stmpdir, sizeof(stmpdir), SIP_MSG_SERV_SUFFIX);
      cpr_set_sockun_addr(&sip_serv_sock_addr, stmpdir, 0);
    }

    /*
     * Create IPC between the message queue thread and this main
     * thread.
     */
    sip_ipc_serv_socket = sip_create_IPC_sock(sip_serv_sock_addr.sun_path);

    if (sip_ipc_serv_socket == INVALID_SOCKET) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_create_IPC_sock() failed:"
                          " errno=%d\n", fname, cpr_errno);
        return;
    }

    /*
     * On Win32 platform, the random seed is stored per thread; therefore,
     * each thread needs to seed the random number.  It is recommended by
     * MS to do the following to ensure randomness across application
     * restarts.
     */
    cpr_srand((unsigned int)time(NULL));

    /*
     * Set read IPC socket
     */
    sip_platform_task_set_read_socket(sip_ipc_serv_socket);

    /*
     * Let the message queue waiting thread know that the main
     * thread is ready.
     */
    main_thread_ready = TRUE;

    /*
     * Main Event Loop
     * - Forever-loop exits in sip_process_int_msg()::THREAD_UNLOAD
     */
    while (TRUE) {
        /*
         * Wait on events or timeout
         */
        sip_read_fds = read_fds;

        // start off by init to zero
        FD_ZERO(&sip_write_fds);
        // now look for sockets where data has been queued up
        for (i = 0; i < MAX_CONNECTIONS; i++) {
            entry = sip_tcp_conn_tab + i;
            if (-1 != entry->fd && entry->sendQueue && sll_count(entry->sendQueue)) {
                FD_SET(entry->fd, &sip_write_fds);
            }
        }

        pending_operations = cprSelect((nfds + 1),
                                       &sip_read_fds,
                                       &sip_write_fds,
                                       NULL, NULL);
        if (pending_operations == SOCKET_ERROR) {
            CCSIP_DEBUG_ERROR(SIP_F_PREFIX"cprSelect() failed: errno=%d."
                " Recover by initiating sip restart\n",
                              fname, cpr_errno);
            /*
             * If we have come here, then either read socket related to
             * sip_ipc_serv_socket has got corrupted, or one of the write
             * socket related to cucm tcp/tls connection.
             * We will recover, by first clearing all fds, then re-establishing
             * the connection with sip-msgq by listening on
             * sip_ipc_serv_socket.
             */
            sip_platform_task_init(); /* this clear FDs */
            sip_platform_task_set_read_socket(sip_ipc_serv_socket);

            /*
             * Since all sockets fds have been cleared above, we can not anyway
             * send or receive msg from cucm. So, there is no point
             * trying to send registration cancel msg to cucm. Also, a
             * call may be active, and in that case we do not want to
             * un-register. So, by setting sip_reg_all_failed to true, we
             * make sure that no registration cancelation attempt is made.
             */
            sip_reg_all_failed = TRUE;
            platform_reset_req(DEVICE_RESTART);
            continue;
        } else if (pending_operations) {
            /*
             * Listen socket is set only if UDP transport has been
             * configured. So see if the select return was for read
             * on the listen socket.
             */
            if ((listen_socket != INVALID_SOCKET) &&
                (sip.taskInited == TRUE) &&
                FD_ISSET(listen_socket, &sip_read_fds)) {
                sip_platform_udp_read_socket(listen_socket);
                pending_operations--;
            }

            /*
             * Check IPC for internal message queue
             */
            if (FD_ISSET(sip_ipc_serv_socket, &sip_read_fds)) {
                /* read the message to flush the buffer */
                sip_process_int_msg();
                pending_operations--;
            }

            /*
             * Check all sockets for stuff to do
             */
            for (i = 0; ((i < MAX_SIP_CONNECTIONS) &&
                         (pending_operations > 0)); i++) {
                if ((sip_conn.read[i] != INVALID_SOCKET) &&
                    FD_ISSET(sip_conn.read[i], &sip_read_fds)) {
                    /*
                     * Assume tcp
                     */
                    sip_tcp_read_socket(sip_conn.read[i]);
                    pending_operations--;
                }
                if ((sip_conn.write[i] != INVALID_SOCKET) &&
                    FD_ISSET(sip_conn.write[i], &sip_write_fds)) {
                    int connid;

                    connid = sip_tcp_fd_to_connid(sip_conn.write[i]);
                    if (connid >= 0) {
                        sip_tcp_resend(connid);
                    }
                    pending_operations--;
                }
            }
        }
    }
}
Пример #3
0
/**
 *  The function is a thread loop that waits on SIP message queue
 *  visible for the external components (sip_msgq). The thread is used
 *  to avoid having the main task loop from having to set a small time
 *  waiting on select() to poll inter-thread messages. The small waiting
 *  time on select() to poll internal messages queue increases the
 *  unnecessary of waking up when system is idle. On the platform that
 *  power conservative is critical such as handheld phone, waking up
 *  periodically is not good for battery life.
 *
 *  This thread splits the message queue waiting function from the
 *  main thread waiting on select(). This thread simply listens on the
 *  internal message queue and signal to the main thread via IPC socket
 *  or local socket trigger. Therefore the main thread can uniformly
 *  process internal message event and the network event via select().
 *  The small internal poll time on select() can be
 *  avoided.
 *
 *  @param[in] arg - pointer to SIP main thread's message queue.
 *
 *  @return None.
 *
 *  @pre     (arg != NULL)
 */
void sip_platform_task_msgqwait (void *arg)
{
    const char    *fname = "sip_platform_task_msgqwait";
    cprMsgQueue_t *msgq = (cprMsgQueue_t *)arg;
    unsigned int  wait_main_thread = 0;
    phn_syshdr_t  *syshdr;
    void          *msg;
    uint8_t       num_messages = 0;
    uint8_t       response = 0;
    boolean       quit_thread = FALSE;
    char          tempdir[sizeof(sip_serv_sock_addr.sun_path)];

    if (msgq == NULL) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"task msgq is null, exiting", fname);
        return;
    }

    if (platThreadInit("SIP IPCQ task") != 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to attach thread to JVM", fname);
        return;
    }

    /*
     * Wait for SIP main thread ready for IPC connection.
     */
    while (!main_thread_ready) {
        /* Pause for other threads to run while waiting */
        cprSleep(SIP_PAUSE_WAIT_IPC_LISTEN_READY_TIME);

        wait_main_thread++;
        if (wait_main_thread > SIP_MAX_WAIT_FOR_IPC_LISTEN_READY) {
            /* Exceed the number of wait time */
            CCSIP_DEBUG_ERROR(SIP_F_PREFIX"timeout waiting for listening IPC"
                              " socket ready, exiting\n", fname);
            return;
        }
    }

    /*
     * Adjust relative priority of SIP thread.
     */
    (void) cprAdjustRelativeThreadPriority(SIP_THREAD_RELATIVE_PRIORITY);

    /*
     * The main thread is ready. set global client socket address
     * so that the server can send back response.
     */
    sip_get_sock_dir(tempdir, sizeof(tempdir), SIP_MSG_CLNT_SUFFIX);
    cpr_set_sockun_addr(&sip_clnt_sock_addr, tempdir, 0);

    sip_ipc_clnt_socket = sip_create_IPC_sock(sip_clnt_sock_addr.sun_path);

    if (sip_ipc_clnt_socket == INVALID_SOCKET) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_create_IPC_sock() failed,"
                          "  exiting\n", fname);
        return;
    }

    while (quit_thread == FALSE) {
        msg = cprGetMessage(msgq, TRUE, (void **) &syshdr);
        while (msg != NULL) {
            /*
             * There is a message to be forwarded to the main SIP
             * thread for processing.
             */
            sip_int_msgq_buf[num_messages].msg    = msg;
            sip_int_msgq_buf[num_messages].syshdr = syshdr;
            num_messages++;

            switch (syshdr->Cmd) {
            case THREAD_UNLOAD:
                thread_ended(THREADMON_MSGQ);
                quit_thread = TRUE;
                    break;
                default:
                    break;
            }

            if (num_messages == MAX_SIP_MESSAGES) {
                /*
                 * Limit the number of messages passed to the main SIP
                 * thread to MAX_SIP_MESSAGES since SIP main thread only
                 * process messages up to MAX_SIP_MESSAGES at a time.
                 */
                break;
            }
            /*
             * Check to see if there is more message on the queue
             * before sending IPC message trigger to the main SIP
             * thread. This is to minimize the overhead of the
             * the main SIP thread in processing select().
             */
            msg = cprGetMessage(msgq, 0, (void **) &syshdr);
        }

        if (num_messages) {
            CCSIP_DEBUG_TASK(DEB_F_PREFIX"%d msg available on msgq", DEB_F_PREFIX_ARGS(SIP_MSG_QUE, fname), num_messages);
            /*
             * There are some number of messages sent to the main thread,
             * trigger the main SIP thread via IPC to process the message.
             */
            if (cprSendTo(sip_ipc_clnt_socket, (void *)&num_messages,
                          sizeof(num_messages), 0,
                          (cpr_sockaddr_t *)&sip_serv_sock_addr,
                          cpr_sun_len(sip_serv_sock_addr)) < 0) {
                CCSIP_DEBUG_ERROR(SIP_F_PREFIX"send IPC failed errno=%d", fname, cpr_errno);
            }

            if (FALSE == quit_thread) {
            	/*
            	 * Wait for main thread to signal us to get more message.
            	 */
            	if (cprRecvFrom(sip_ipc_clnt_socket, &response,
            			sizeof(response), 0, NULL, NULL) < 0) {
            		CCSIP_DEBUG_ERROR(SIP_F_PREFIX"read IPC failed:"
            				" errno=%d\n", fname, cpr_errno);
            	}
            	num_messages = 0;
            }
        }
    }
    cprCloseSocket(sip_ipc_clnt_socket);
    unlink(sip_clnt_sock_addr.sun_path); // removes tmp file
}
Пример #4
0
void
GSMTask (void *arg)
{
    static const char fname[] = "GSMTask";
    void           *msg;
    phn_syshdr_t   *syshdr;
    boolean        release_msg = TRUE;

    /*
     * Get the GSM message queue handle
     * A hack until the tasks in irx are
     * CPRized.
     */
    gsm_msg_queue = (cprMsgQueue_t) arg;
    if (!gsm_msg_queue) {
        GSM_ERR_MSG(GSM_F_PREFIX"invalid input, exiting\n", fname);
        return;
    }

    if (platThreadInit("GSMTask") != 0) {
        return;
    }

    /*
     * Adjust relative priority of GSM thread.
     */
    (void) cprAdjustRelativeThreadPriority(GSM_THREAD_RELATIVE_PRIORITY);

    /*
     * Initialize all the GSM modules
     */
    lsm_init();
    fsm_init();
    fim_init();
    gsm_init();
    dcsm_init();

    cc_init();

    fsmutil_init_shown_calls_ci_map();
    /*
     * On Win32 platform, the random seed is stored per thread; therefore,
     * each thread needs to seed the random number.  It is recommended by
     * MS to do the following to ensure randomness across application
     * restarts.
     */
    cpr_srand((unsigned int)time(NULL));

    /*
     * Cache random numbers for SRTP keys
     */
    gsmsdp_cache_crypto_keys();

    while (1) {

        release_msg = TRUE;

        msg = cprGetMessage(gsm_msg_queue, TRUE, (void **) &syshdr);
        if (msg) {
            switch (syshdr->Cmd) {
            case TIMER_EXPIRATION:
                gsm_process_timer_expiration(msg);
                break;

            case GSM_SIP:
            case GSM_GSM:
                release_msg = gsm_process_msg(syshdr->Cmd, msg);
                break;

            case DP_MSG_INIT_DIALING:
            case DP_MSG_DIGIT_STR:
            case DP_MSG_STORE_DIGIT:
            case DP_MSG_DIGIT:
            case DP_MSG_DIAL_IMMEDIATE:
            case DP_MSG_REDIAL:
            case DP_MSG_ONHOOK:
            case DP_MSG_OFFHOOK:
            case DP_MSG_UPDATE:
            case DP_MSG_DIGIT_TIMER:
            case DP_MSG_CANCEL_OFFHOOK_TIMER:
                dp_process_msg(syshdr->Cmd, msg);
                break;

            case SUB_MSG_B2BCNF_SUBSCRIBE_RESP:
            case SUB_MSG_B2BCNF_NOTIFY:
            case SUB_MSG_B2BCNF_TERMINATE:
                sub_process_b2bcnf_msg(syshdr->Cmd, msg);
                break;

            case SUB_MSG_FEATURE_SUBSCRIBE_RESP:
            case SUB_MSG_FEATURE_NOTIFY:
            case SUB_MSG_FEATURE_TERMINATE:
                sub_process_feature_msg(syshdr->Cmd, msg);
                break;

            case SUB_MSG_KPML_SUBSCRIBE:
            case SUB_MSG_KPML_TERMINATE:
            case SUB_MSG_KPML_NOTIFY_ACK:
            case SUB_MSG_KPML_SUBSCRIBE_TIMER:
            case SUB_MSG_KPML_DIGIT_TIMER:
                kpml_process_msg(syshdr->Cmd, msg);
                break;

            case REG_MGR_STATE_CHANGE:
                gsm_reset();
                break;
            case THREAD_UNLOAD:
                destroy_gsm_thread();
                break;

            default:
                GSM_ERR_MSG(GSM_F_PREFIX"Unknown message\n", fname);
                break;
            }

            cprReleaseSysHeader(syshdr);
            if (release_msg == TRUE) {
                cprReleaseBuffer(msg);
            }
            
            /* Check if there are pending messages for dcsm 
             * if it in the right state perform its operation 
             */
            dcsm_process_jobs();
        }
    }
}