/**
 *  sip_process_int_msg - process internal IPC message from the
 *  the message queue waiting thread.
 *
 *  @param - none.
 *
 *  @return none.
 */
static void sip_process_int_msg (void)
{
    const char    *fname = "sip_process_int_msg";
    ssize_t       rcv_len;
    uint8_t       num_messages = 0;
    uint8_t       response = 0;
    sip_int_msg_t *int_msg;
    void          *msg;
    phn_syshdr_t  *syshdr;

    /* read the msg count from the IPC socket */
    rcv_len = cprRecvFrom(sip_ipc_serv_socket, &num_messages,
                          sizeof(num_messages), 0, NULL, NULL);

    if (rcv_len < 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"read IPC failed:"
                          " errno=%d\n", fname, cpr_errno);
        return;
    }

    if (num_messages == 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"message queue is empty!\n", fname);
        return;
    }

    if (num_messages > MAX_SIP_MESSAGES) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"number of  messages on queue exceeds maximum %d\n", fname,
                          num_messages);
        num_messages = MAX_SIP_MESSAGES;
    }

    /* process messages */
    int_msg = &sip_int_msgq_buf[0];
    while (num_messages) {
        msg    = int_msg->msg;
        syshdr = int_msg->syshdr;
        if (msg != NULL && syshdr != NULL) {
            SIPTaskProcessListEvent(syshdr->Cmd, msg, syshdr->Usr.UsrPtr,
                syshdr->Len);
            cprReleaseSysHeader(syshdr);

            int_msg->msg    = NULL;
            int_msg->syshdr = NULL;
        }

        num_messages--;  /* one less message to work on */
        int_msg++;       /* advance to the next message */
    }

    /*
     * Signal message queue waiting thread to get more messages.
     */
    if (cprSendTo(sip_ipc_serv_socket, (void *)&response,
                  sizeof(response), 0,
                  (cpr_sockaddr_t *)&sip_clnt_sock_addr,
                  cpr_sun_len(sip_clnt_sock_addr)) < 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%d sending IPC\n", fname);
    }
}
int
sip_platform_udp_channel_read (cpr_socket_t s,
                               cprBuffer_t buf,
                               uint16_t *len,
                               cpr_sockaddr_t *soc_addr,
                               cpr_socklen_t *soc_addr_len)
{
    static const char *fname = "sip_platform_udp_channel_read";
    int bytes_read;
    // NOT USED: cpr_sockaddr_in_t *addr = (cpr_sockaddr_in_t *)soc_addr;

    bytes_read = cprRecvFrom(s, buf, CPR_MAX_MSG_SIZE, 0, soc_addr,
                             soc_addr_len);

    switch (bytes_read) {
    case SOCKET_ERROR:
        /*
         * If no data is available to read (CPR_EWOULDBLOCK),
         * for non-blocking socket, it is not an error.
         */
        cpr_free(buf);
        *len = 0;
        if (cpr_errno != CPR_EWOULDBLOCK) {
            CCSIP_DEBUG_ERROR(SIP_F_PREFIX"fd[%d]\n", fname, s);
            CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_SYSTEMCALL_FAILED),
                              fname, "cprRecvFrom", cpr_errno);
            return SIP_ERROR;
        }
        /*
         * Will continue reading when data arrives at socket
         */
        break;
    case 0:
        /*
         * Return value 0 is OK.  This does NOT mean the connection
         * has closed by the peer, as with TCP sockets.  With UDP
         * sockets, there is no such thing as closing a connection.
         */
        CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"No data on fd %d\n", DEB_F_PREFIX_ARGS(SIP_SDP, fname), s);
        cpr_free(buf);
        *len = 0;
        break;
    default:
        /* PKT has been read */
        CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Recvd on fd %d\n", DEB_F_PREFIX_ARGS(SIP_SDP, fname), s);
        *len = (uint16_t) bytes_read;
        break;
    }

    return SIP_OK;
}
/**
 *  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
}
/**
 *  sip_process_int_msg - process internal IPC message from the
 *  the message queue waiting thread.
 *
 *  @param - none.
 *
 *  @return none.
 */
static void sip_process_int_msg (void)
{
    const char    *fname = "sip_process_int_msg";
    ssize_t       rcv_len;
    uint8_t       num_messages = 0;
    uint8_t       response = 0;
    sip_int_msg_t *int_msg;
    void          *msg;
    phn_syshdr_t  *syshdr;

    /* read the msg count from the IPC socket */
    rcv_len = cprRecvFrom(sip_ipc_serv_socket, &num_messages,
                          sizeof(num_messages), 0, NULL, NULL);

    if (rcv_len < 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"read IPC failed:"
                          " errno=%d\n", fname, cpr_errno);
        return;
    }

    if (num_messages == 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"message queue is empty!\n", fname);
        return;
    }

    if (num_messages > MAX_SIP_MESSAGES) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"number of  messages on queue exceeds maximum %d\n", fname,
                          num_messages);
        num_messages = MAX_SIP_MESSAGES;
    }

    /* process messages */
    int_msg = &sip_int_msgq_buf[0];
    while (num_messages) {
        msg    = int_msg->msg;
        syshdr = int_msg->syshdr;
        if (msg != NULL && syshdr != NULL) {
            if (syshdr->Cmd == THREAD_UNLOAD) {
                /*
                 * Cleanup here, as SIPTaskProcessListEvent wont return.
                 * - Remove last tmp file and tmp dir.
                 */
                cprCloseSocket(sip_ipc_serv_socket);
                unlink(sip_serv_sock_addr.sun_path);

                char stmpdir[sizeof(sip_serv_sock_addr.sun_path)];
                PR_snprintf(stmpdir, sizeof(stmpdir), SIP_IPC_TEMP_PATH, getpid());
                if (rmdir(stmpdir) != 0) {
                    CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to remove temp dir\n",
                                      fname);
                }
            }
            SIPTaskProcessListEvent(syshdr->Cmd, msg, syshdr->Usr.UsrPtr,
                syshdr->Len);
            cprReleaseSysHeader(syshdr);

            int_msg->msg    = NULL;
            int_msg->syshdr = NULL;
        }

        num_messages--;  /* one less message to work on */
        int_msg++;       /* advance to the next message */
    }

    /*
     * Signal message queue waiting thread to get more messages.
     */
    if (cprSendTo(sip_ipc_serv_socket, (void *)&response,
                  sizeof(response), 0,
                  (cpr_sockaddr_t *)&sip_clnt_sock_addr,
                  cpr_sun_len(sip_clnt_sock_addr)) < 0) {
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"%d sending IPC\n", fname);
    }
}