bool LSGmainAttachPalmService(LSPalmService *psh, GMainLoop *mainLoop, LSError *lserror) { _LSErrorIfFail(psh != NULL, lserror); _LSErrorIfFail(mainLoop != NULL, lserror); bool retVal; retVal = LSGmainAttach(psh->public_sh, mainLoop, lserror); if (!retVal) return retVal; retVal = LSGmainAttach(psh->private_sh, mainLoop, lserror); if (!retVal) return retVal; return retVal; }
/** * @brief Block till incoming message is ready. This should only be * called by custom mainloops. * * @param sh * @param *message allocated store of next message from queue, NULL if queue is empty. * You MUST call LSMessageUnref() to free this message. * @param lserror * * @retval */ bool LSCustomWaitForMessage(LSHandle *sh, LSMessage **message, LSError *lserror) { _LSErrorIfFail(sh != NULL, lserror); _LSErrorIfFail(message != NULL, lserror); LSHANDLE_VALIDATE(sh); bool retVal; /* If the incoming queue contains messages, return immediately */ retVal = LSCustomFetchMessage(sh, message, lserror); if (!retVal) return false; if (*message) return true; /* install custom message callback if not done already */ if (G_UNLIKELY(sh->transport->msg_handler != _LSCustomMessageHandler)) { sh->transport->msg_handler = _LSCustomMessageHandler; sh->transport->msg_context = sh; sh->transport->mainloop_context = g_main_context_new(); if (!sh->transport->mainloop_context) { _LSErrorSet(lserror, -ENOMEM, "OOM"); return false; } _LSTransportAddInitialWatches(sh->transport, sh->transport->mainloop_context); } /* * Run an interation of the context: g_main_context_iteration, which * will call our special custom message callback and add to the queue of * messages */ g_main_context_iteration(sh->transport->mainloop_context, TRUE); /* Fetch 1 message off incoming queue. */ retVal = LSCustomFetchMessage(sh, message, lserror); if (!retVal) return false; return true; }
/** * @brief Attach a service to a glib mainloop. * * @param sh * @param mainLoop * @param lserror * * @retval */ bool LSGmainAttach(LSHandle *sh, GMainLoop *mainLoop, LSError *lserror) { _LSErrorIfFail(sh != NULL, lserror); _LSErrorIfFail(mainLoop != NULL, lserror); LSHANDLE_VALIDATE(sh); GMainContext *context = g_main_loop_get_context(mainLoop); _LSErrorIfFailMsg(context != NULL, lserror, -1, "%s: %s", __FUNCTION__, ": No maincontext."); _LSTransportGmainAttach(sh->transport, context); sh->context = g_main_context_ref(context); return true; }
/** * @brief Get the unique serial of this message. Do not confuse with * LSMessageGetResponseToken(). * * @param message * * @retval */ LSMessageToken LSMessageGetToken(LSMessage *message) { _LSErrorIfFail(NULL != message, NULL); LSMessageToken serial = _LSTransportMessageGetToken(message->transport_msg); return serial; }
/** * @brief Obtain a unique token identifying the sender. * * @param message * * @retval */ const char * LSMessageGetSender(LSMessage *message) { _LSErrorIfFail(NULL != message, NULL); const char *sender = _LSTransportMessageGetSenderUniqueName(message->transport_msg); return sender; }
/** * @brief Get the name of the service that sent the message. (NULL if the * sender didn't register a service name) * * @param message * * @retval service_name if service sending the message has a name * @retval NULL otherwise */ const char * LSMessageGetSenderServiceName(LSMessage *message) { _LSErrorIfFail(NULL != message, NULL); const char *service_name = _LSTransportMessageGetSenderServiceName(message->transport_msg); return service_name; }
/** * @brief Sets the priority level on the associated GSources for * the service connection. * * This should be called after LSGmainAttach(). * * See glib documentation for GSource priority levels. * * @param sh * @param lserror * * @retval */ bool LSGmainSetPriority(LSHandle *sh, int priority, LSError *lserror) { _LSErrorIfFail(sh != NULL, lserror); LSHANDLE_VALIDATE(sh); return _LSTransportGmainSetPriority(sh->transport, priority, lserror); }
/** * @brief Detach a service from a glib mainloop. You should NEVER use this * function unless you are fork()'ing without exec()'ing and know what you are * doing. This will perform nearly all the same cleanup as LSUnregister(), with * the exception that it will not send out shutdown messages or flush any * buffers. It is intended to be used only when fork()'ing so that your child * process can continue without interfering with the parent's file descriptors, * since open file descriptors are duplicated during a fork(). * * @param sh * @param lserror * * @retval */ bool LSGmainDetach(LSHandle *sh, LSError *lserror) { _LSErrorIfFail(sh != NULL, lserror); _LSErrorIfFailMsg(sh->context != NULL, lserror, -1, "%s: %s", __FUNCTION__, ": No maincontext."); /* We "unregister" without actually flushing or sending shutdown messages */ return _LSUnregisterCommon(sh, false, LSHANDLE_GET_RETURN_ADDR(), lserror); }
/** * @brief Get the method name of the message. * * @param message * * @retval */ const char * LSMessageGetMethod(LSMessage *message) { _LSErrorIfFail(NULL != message, NULL); if (message->method) return message->method; message->method = _LSTransportMessageGetMethod(message->transport_msg); return message->method; }
/** * @brief Get the category of this message. * * @param message * * @retval */ const char * LSMessageGetCategory(LSMessage *message) { _LSErrorIfFail(NULL != message, NULL); if (message->category) return message->category; message->category = _LSTransportMessageGetCategory(message->transport_msg); return message->category; }
/** * @brief Get the response token associated with this message this will match * with the LSMessageGetToken() of the original call. * * For signals, the response token is supplanted with the original token * returned from LSSignalCall(). * * @param reply * * @retval */ LSMessageToken LSMessageGetResponseToken(LSMessage *reply) { _LSErrorIfFail(NULL != reply, NULL); if (reply->responseToken) return reply->responseToken; reply->responseToken = _LSTransportMessageGetReplyToken(reply->transport_msg); return reply->responseToken; }
/** * @brief Convenience function to pretty print a message. * * @param lmsg * @param out * * @retval */ bool LSMessagePrint(LSMessage *message, FILE *out) { _LSErrorIfFail(NULL != message, NULL); fprintf(out, "%s/%s <%s>\n", LSMessageGetCategory(message), LSMessageGetMethod(message), LSMessageGetPayload(message)); return true; }
/** * @brief Get the payload of this message. * * @param message * * @retval */ const char * LSMessageGetPayload(LSMessage *message) { _LSErrorIfFail(message != NULL, NULL); if (message->payload) { return message->payload; } message->payload = _LSTransportMessageGetPayload(message->transport_msg); return message->payload; }
bool LSGmainSetPriorityPalmService(LSPalmService *psh, int priority, LSError *lserror) { bool retVal; _LSErrorIfFail(psh != NULL, lserror); if (psh->public_sh) { retVal = LSGmainSetPriority(psh->public_sh, priority, lserror); if (!retVal) return false; } if (psh->private_sh) { retVal = LSGmainSetPriority(psh->private_sh, priority, lserror); if (!retVal) return false; } return true; }
/** * @brief Checks if the message has subscription field with * subscribe=true * * @param message * * @retval true if has subscribe=true, false otherwise */ bool LSMessageIsSubscription(LSMessage *message) { bool ret = false; struct json_object *sub_object = NULL; const char *payload = LSMessageGetPayload(message); struct json_object *object = json_tokener_parse(payload); if (JSON_ERROR(object)) goto exit; if (!json_object_object_get_ex(object, "subscribe", &sub_object) || JSON_ERROR(sub_object)) goto exit; _LSErrorIfFail(json_object_get_type(sub_object) == json_type_boolean, NULL); ret = json_object_get_boolean(sub_object); exit: if (!JSON_ERROR(object)) json_object_put(object); return ret; }
/** * @brief Send a reply to a message using the bus identified by LSHandle. * * To use the same bus upon which the message arrived, it is * recommended to use LSMessageRespond(). * * @param sh * @param lsmsg * @param replyPayload * @param lserror * * @retval */ bool LSMessageReply(LSHandle *sh, LSMessage *lsmsg, const char *replyPayload, LSError *lserror) { _LSErrorIfFail (sh != NULL, lserror); _LSErrorIfFail (lsmsg != NULL, lserror); _LSErrorIfFail (replyPayload != NULL, lserror); LSHANDLE_VALIDATE(sh); if (unlikely(_ls_enable_utf8_validation)) { if (!g_utf8_validate (replyPayload, -1, NULL)) { _LSErrorSet(lserror, -EINVAL, "%s: payload is not utf-8", __FUNCTION__); return false; } } if (unlikely(strcmp(replyPayload, "") == 0)) { _LSErrorSet(lserror, -EINVAL, "Empty payload is not valid JSON. Use {}"); return false; } if (DEBUG_TRACING) { if (DEBUG_VERBOSE) { g_debug("TX: LSMessageReply token <<%ld>> %s", LSMessageGetToken(lsmsg), replyPayload); } else { g_debug("TX: LSMessageReply token <<%ld>>", LSMessageGetToken(lsmsg)); } } if (_LSTransportMessageGetType(lsmsg->transport_msg) == _LSTransportMessageTypeReply) { g_warning("%s: \nYou are attempting to send a reply to a reply message. \n" "I'm going to allow this for now to more easily reproduce some bugs \n" "we encountered with services using LSCustomWaitForMessage \n" "receiving a reply-to-a-reply, but soon this will return an error.", __FUNCTION__); } if (unlikely(LSMessageGetConnection(lsmsg) != sh)) { _LSErrorSet(lserror, -EINVAL, "%s: You are replying to message on different bus.\n" " If you can't identify which bus, " "try LSMessageRespond() instead.", __FUNCTION__); return false; } bool retVal = _LSTransportSendReply(lsmsg->transport_msg, replyPayload, lserror); return retVal; }
/* * This returns NULL or a ref'd message which you must unref when finished * with */ bool LSFetchQueueWaitForMessage(LSFetchQueue *fq, LSMessage **ret_message, LSError *lserror) { _LSErrorIfFail(fq != NULL, lserror); _LSErrorIfFail(ret_message != NULL, lserror); GSList *iter; //int nfd = -1; bool retVal; bool do_iteration = true; /* If we have already pending data we don't want to block on the iteration * since there may not be any more data coming */ for (iter = fq->sh_list; iter != NULL; iter = iter->next) { LSHandle *sh = (LSHandle*)iter->data; if (_FetchMessageQueueSize(sh) > 0 || !LSCustomMessageQueueIsEmpty(sh->custom_message_queue)) { do_iteration = false; break; } } /* * Run an interation of the context: g_main_context_iteration, which * will call our special custom message callback and add to the queue of * messages */ if (do_iteration) { g_main_context_iteration(fq->main_context, TRUE); } /********** * Dispatch **********/ /* We treat the dispatch list like a circular list. Stop when we see * the first message, or if we see the first element. * * This avoids starvation of any single connection. */ if (!fq->dispatch_iter) { fq->dispatch_iter = fq->sh_list; } GSList *first = fq->dispatch_iter; LSMessage *message = NULL; while (fq->dispatch_iter != NULL) { LSHandle *sh = (LSHandle*)fq->dispatch_iter->data; //g_debug("%d Fetching message from %p %s", ++i, sh, sh->name); /* Fetch 1 message off incoming queue. */ retVal = LSCustomFetchMessage(sh, &message, lserror); if (!retVal) { g_message("LSCustomFetchMessage returned false."); return false; } /* Get next connection. */ fq->dispatch_iter = fq->dispatch_iter->next; if (!fq->dispatch_iter) { //g_message("dispatch iter end"); fq->dispatch_iter = fq->sh_list; } if (fq->dispatch_iter == first) { //g_debug("Reached the first %p stopping...", first->data); fq->dispatch_iter = NULL; } /* Found a message! return it to user */ if (message != NULL) break; } *ret_message = message; return true; }