/** 
* @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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
/**
* @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;
}
Beispiel #5
0
// 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;
}
Beispiel #6
0
/** 
* @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;
}
Beispiel #8
0
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;
}