/** * @brief Acquire an iterator to iterate through the subscription * for 'key'. * * @param sh * @param key * @param *ret_iter * @param lserror * * @retval */ bool LSSubscriptionAcquire(LSHandle *sh, const char *key, LSSubscriptionIter **ret_iter, LSError *lserror) { LSHANDLE_VALIDATE(sh); _Catalog *catalog = sh->catalog; LSSubscriptionIter *iter = g_new0(LSSubscriptionIter, 1); _CatalogLock(catalog); _SubList *tokens = _CatalogGetSubList_unlocked(catalog, key); iter->tokens = _SubListDup(tokens); _CatalogUnlock(catalog); iter->catalog = catalog; iter->index = -1; iter->seen_messages = NULL; if (ret_iter) { *ret_iter = iter; } return true; }
/** * @brief Pop a message from the incoming queue, non blocking. This should * only be called by custom mainloops. Do NOT call this if you intend * to use callback tables registered by LSRegisterCategory(). * * To dispatch to callback tables use LSCustomDispatchMessage() * instead. * * @param sh * @param *ret_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 LSCustomFetchMessage(LSHandle *sh, LSMessage **ret_message, LSError *lserror) { LSHANDLE_VALIDATE(sh); return _FetchMessageQueueGet(sh, ret_message, lserror); }
/** * @brief Add a subscription to a list associated with 'key'. * * @param sh * @param key * @param message * @param lserror * * @retval */ bool LSSubscriptionAdd(LSHandle *sh, const char *key, LSMessage *message, LSError *lserror) { LSHANDLE_VALIDATE(sh); return _CatalogAdd(sh->catalog, key, message, lserror); }
/** * @brief Remove cancellation function callback. * * Function callback removed from list not changing relative order of other elements. * Both function callback and context should match to remove. * * @param sh * @param cancelNotifyFunction * @param ctx * @param lserror * * @retval */ bool LSCallCancelNotificationRemove(LSHandle *sh, LSCancelNotificationFunc cancelNotifyFunction, void *ctx, LSError *lserror) { LSHANDLE_VALIDATE(sh); return _CatalogRemoveCancelNotification(sh->catalog, cancelNotifyFunction, ctx, lserror); }
/** * @brief Wake up the user's custom mainloop. Only works if you've * implented a custom mainloop via LSCustomGetFds() * * @param sh * @param lserror * * @retval */ bool LSCustomWakeUp(LSHandle *sh, LSError *lserror) { LSHANDLE_VALIDATE(sh); g_main_context_wakeup(sh->transport->mainloop_context); return true; }
/** * @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 Register a callback to be called when subscription cancelled. * * Callback may be called when client cancels subscription via LSCallCancel() * or if the client drops off the bus. * * @param sh * @param cancelFunction * @param ctx * @param lserror * * @retval */ bool LSSubscriptionSetCancelFunction(LSHandle *sh, LSFilterFunc cancelFunction, void *ctx, LSError *lserror) { LSHANDLE_VALIDATE(sh); sh->catalog->cancel_function = cancelFunction; sh->catalog->cancel_function_ctx = ctx; return true; }
/** * @brief Posts a message to all in subscription '/category/method'. * This is equivalent to: * LSSubscriptionReply(sh, '/category/method', payload, lserror) * * @deprecated Please use LSSubscriptionReply() instead. * * @param sh * @param category * @param method * @param payload * @param lserror * * @retval */ bool LSSubscriptionPost(LSHandle *sh, const char *category, const char *method, const char *payload, LSError *lserror) { LSHANDLE_VALIDATE(sh); bool retVal = false; char *key = _LSMessageGetKindHelper(category, method); retVal = LSSubscriptionReply(sh, key, payload, lserror); g_free(key); 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 Sends a message to subscription list with name 'key'. * * @param sh * @param key * @param payload * @param lserror * * @retval */ bool LSSubscriptionReply(LSHandle *sh, const char *key, const char *payload, LSError *lserror) { LSHANDLE_VALIDATE(sh); bool retVal = true; _Catalog *catalog = sh->catalog; _CatalogLock(catalog); _SubList *tokens = _CatalogGetSubList_unlocked(catalog, key); if (!tokens) { retVal = true; goto cleanup; } int i; for (i = 0; i < tokens->len; i++) { char *tok = g_ptr_array_index(tokens, i); _Subscription *subs = g_hash_table_lookup(catalog->token_map, tok); if (!subs) continue; LSMessage *message = subs->message; retVal = LSMessageReply(sh, message, payload, lserror); if (!retVal) goto cleanup; } cleanup: _CatalogUnlock(catalog); return retVal; }
/** * @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; }