/** * @brief Send a reply. * * @param sh * @param message * @param replyPayload * @param error * * @deprecated Use LSMessageReply() instead. * * @retval */ LS_DEPRECATED bool LSMessageReturn(LSHandle *sh, LSMessage *lsmsg, const char *replyPayload, LSError *lserror) { _LSErrorSet(lserror, LS_ERROR_CODE_DEPRECATED, LS_ERROR_TEXT_DEPRECATED); return false; }
static bool _CatalogRemoveCancelNotification(_Catalog *catalog, LSCancelNotificationFunc function, void *context, LSError *lserror) { bool retVal = false; _CatalogLock(catalog); if (!catalog->cancel_notify_list) { _LSErrorSet(lserror, MSGID_LS_CATALOG_ERR, -1, "Cancel notification list not available"); goto cleanup; } int idx; for (idx = 0; idx < catalog->cancel_notify_list->len; ++idx) { _SubscriberCancelNotification *scn = g_ptr_array_index(catalog->cancel_notify_list, idx); if (scn->function == function && scn->context == context) { g_ptr_array_remove_index(catalog->cancel_notify_list, idx); break; } } retVal = true; cleanup: _CatalogUnlock(catalog); return retVal; }
bool _CatalogHandleCancel(_Catalog *catalog, LSMessage *cancelMsg, LSError *lserror) { JSchemaInfo schemaInfo; jschema_info_init(&schemaInfo, jschema_all(), NULL, NULL); const char *sender; int token; jvalue_ref tokenObj = NULL; const char *payload = LSMessageGetPayload(cancelMsg); jvalue_ref object = jdom_parse(j_cstr_to_buffer(payload), DOMOPT_NOOPT, &schemaInfo); if (jis_null(object)) { _LSErrorSet(lserror, MSGID_LS_INVALID_JSON, -EINVAL, "Invalid json"); goto error; } sender = LSMessageGetSender(cancelMsg); if (!jobject_get_exists(object, J_CSTR_TO_BUF("token"), &tokenObj) || tokenObj == NULL || !jis_number(tokenObj)) { _LSErrorSet(lserror, MSGID_LS_INVALID_JSON, -EINVAL, "Invalid json"); goto error; } (void)jnumber_get_i32(tokenObj, &token);/* TODO: handle appropriately */ char *uniqueToken = g_strdup_printf("%s.%d", sender, token); _CatalogCallCancelNotifications(catalog, uniqueToken); _CatalogRemoveToken(catalog, uniqueToken, true); g_free(uniqueToken); j_release(&object); return true; error: j_release(&object); return false; }
/** * @brief If message contains subscribe:true, add the message to subscription list using the default key '/category/method'. * * This is equivalent to LSSubscriptionAdd(sh, key, message, lserror) * where the key is LSMessageGetKind(message). * * @param sh * @param message * @param subscribed * @param lserror * * @retval */ bool LSSubscriptionProcess (LSHandle *sh, LSMessage *message, bool *subscribed, LSError *lserror) { JSchemaInfo schemaInfo; jschema_info_init(&schemaInfo, jschema_all(), NULL, NULL); bool retVal = false; bool subscribePayload = false; jvalue_ref subObj = NULL; const char *payload = LSMessageGetPayload(message); jvalue_ref object = jdom_parse(j_cstr_to_buffer(payload), DOMOPT_NOOPT, &schemaInfo); if (jis_null(object)) { _LSErrorSet(lserror, MSGID_LS_INVALID_JSON, -1, "Unable to parse JSON: %s", payload); goto exit; } if (!jobject_get_exists(object, J_CSTR_TO_BUF("subscribe"), &subObj) || subObj == NULL || !jis_boolean(subObj)) { subscribePayload = false; /* FIXME: I think retVal should be false, but I don't know if anyone * is relying on this behavior. If set to false, make sure to set * LSError */ retVal = true; } else { (void)jboolean_get(subObj, &subscribePayload);/* TODO: handle appropriately */ retVal = true; } if (subscribePayload) { const char *key = LSMessageGetKind(message); retVal = LSSubscriptionAdd(sh, key, message, lserror); } if (retVal && subscribePayload) { *subscribed = true; } else { *subscribed = false; } exit: j_release(&object); return retVal; }
// TODO bool LSFetchQueueWakeUp(LSFetchQueue *fq, LSError *lserror) { if (!fq || !fq->sh_list) { _LSErrorSet(lserror, -1, "LSFetchQueue not initialized."); return false; } LSHandle *sh = (LSHandle*)fq->sh_list->data; if (!sh) { _LSErrorSet(lserror, -1, "No servers associated with FetchQueue."); return false; } g_main_context_wakeup(sh->transport->mainloop_context); return true; }
/** * @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 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; }
static bool _CatalogAdd(_Catalog *catalog, const char *key, LSMessage *message, LSError *lserror) { bool retVal = false; const char *token = LSMessageGetUniqueToken(message); if (!token) { _LSErrorSet(lserror, MSGID_LS_TOKEN_ERR, -1, "Could not get unique token"); return false; } _CatalogLock(catalog); _SubList *list = g_hash_table_lookup(catalog->subscription_lists, key); if (!list) { list = _SubListNew(); g_hash_table_replace(catalog->subscription_lists, g_strdup(key), list); } const char* client_name = LSMessageGetSender(message); if (!client_name) { _LSErrorSet(lserror, MSGID_LS_UNAME_ERR, -1, "Could not get service unique name"); return false; } _SubList *client_list = g_hash_table_lookup(catalog->client_subscriptions, client_name); if (!client_list) { client_list = _SubListNew(); g_hash_table_replace(catalog->client_subscriptions, g_strdup(client_name), client_list); } _Subscription *subs = g_hash_table_lookup(catalog->token_map, token); if (!subs) { subs = _SubscriptionNew(catalog->sh, message); if (subs) { g_hash_table_replace(catalog->token_map, g_strdup(token), subs); } else { goto cleanup; } } LS_ASSERT(subs->message == message); if (!_SubListContains(list, token)) { _SubListAdd(list, g_strdup(token)); } if (!_SubListContains(client_list, token)) { _SubListAdd(client_list, g_strdup(token)); } if (!g_char_ptr_array_contains(subs->keys, key)) { g_ptr_array_add(subs->keys, g_strdup(key)); } retVal = true; cleanup: _CatalogUnlock(catalog); return retVal; }