AJ_Status AJS_HandleAcceptSession(duk_context* ctx, AJ_Message* msg, uint16_t port, uint32_t sessionId, const char* joiner)
{
    uint32_t accept = TRUE;
    SessionInfo* sessionInfo;

    /*
     * Create an entry in the sessions table so we can track this peer
     */
    AJS_GetGlobalStashObject(ctx, "sessions");
    sessionInfo = AllocSessionObject(ctx, joiner);
    /*
     * If there is no handler automatically accept the connection
     */
    AJS_GetAllJoynProperty(ctx, "onPeerConnected");
    if (duk_is_callable(ctx, -1)) {
        /* Empty interface array */
        duk_push_array(ctx);
        AddServiceObject(ctx, sessionInfo, "/", joiner);
        if (AJS_DebuggerIsAttached()) {
            msg = AJS_CloneAndCloseMessage(ctx, msg);
        }
        if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS) {
            AJS_ConsoleSignalError(ctx);
            accept = FALSE;
        } else {
            accept = duk_get_boolean(ctx, -1);
        }
    }
    duk_pop_2(ctx);
    /*
     * It is possible that we already have an outbound session to this peer so if we are not
     * accepting the session we can only delete the entry if the refCount is zero.
     */
    if (accept) {
        ++sessionInfo->refCount;
        sessionInfo->port = port;
        sessionInfo->sessionId = sessionId;
    } else if (sessionInfo->refCount == 0) {
        duk_del_prop_string(ctx, -1, joiner);
    }
    /* Pop sessions object */
    duk_pop(ctx);
    return AJ_BusReplyAcceptSession(msg, accept);
}
Example #2
0
static AJ_Status ExecuteAction(AJ_Message* msg, uint8_t action, void* context)
{
    AJS_Widget* widget = (AJS_Widget*)objectList[OBJ_INDEX(msg->msgId)].context;
    AJ_Status status;
    AJ_Message reply;

    /*
     * Need to make a clone of the message and close the original
     */
    msg = AJS_CloneAndCloseMessage(widget->dukCtx, msg);
    if (!msg) {
        return AJ_ERR_RESOURCES;
    }
    /*
     * Call into JavaScript object to perform action
     */
    status = AJS_CP_ExecuteAction(widget, action);
    if (status == AJ_OK) {
        AJ_MarshalReplyMsg(msg, &reply);
    } else {
        AJ_MarshalStatusMsg(msg, &reply, status);
    }
    return AJ_DeliverMsg(&reply);
}
Example #3
0
static AJ_Status SetWidgetProp(AJ_Message* msg)
{
    AJS_Widget* widget = NULL;
    AJ_Message reply;
    AJ_Status status;
    uint32_t propId;
    const char* vsig;

    AJ_InfoPrintf(("SetWidgetProp %s\n", msg->objPath));

    status = AJ_UnmarshalPropertyArgs(msg, &propId, &vsig);
    /*
     * Two levels of variant because Set always uses a variant and the property type for the widget
     * is not known until runtime so is specified as a variant type in the property widget interface.
     */
    if (status == AJ_OK) {
        status = AJ_UnmarshalVariant(msg, &vsig);
    }
    if (status == AJ_OK) {
        status = AJ_UnmarshalVariant(msg, &vsig);
    }
    if (status == AJ_OK) {
        widget = (AJS_Widget*)objectList[OBJ_INDEX(propId)].context;
        /*
         * Value is the only property that is writeable. Figure out how to unmarshal it.
         */
        switch (widget->property.wdt.signature[0]) {
        case 'i':
            status = AJ_UnmarshalArgs(msg, "i", &widget->property.val.i);
            break;

        case 'q':
            status = AJ_UnmarshalArgs(msg, "q", &widget->property.val.q);
            break;

        case 'b':
            status = AJ_UnmarshalArgs(msg, "b", &widget->property.val.b);
            break;

        case 'd':
            status = AJ_UnmarshalArgs(msg, "d", &widget->property.val.d);
            break;

        case 's':
            status = AJ_UnmarshalArgs(msg, "s", &widget->property.val.s);
            break;

        default:
            {
                AJ_Arg st;
                uint16_t propertyType;
                status = AJ_UnmarshalContainer(msg, &st, AJ_ARG_STRUCT);
                if (status != AJ_OK) {
                    break;
                }
                status = AJ_UnmarshalArgs(msg, "q", &propertyType);
                if (status != AJ_OK) {
                    break;
                }
                /*
                 * For some reason the implementors of the control panel service used 0/1 to
                 * distingsuish between date/time rather than 1/2. Incrementing the property type
                 * fixes this oversight.
                 */
                if (++propertyType != widget->property.wdt.propertyType) {
                    status = AJ_ERR_INVALID;
                    break;
                }
                if (propertyType == TIME_VALUE_PROPERTY) {
                    status = AJ_UnmarshalArgs(msg, "(qqq)", &widget->property.val.time.hour, &widget->property.val.time.minute, &widget->property.val.time.second);
                } else {
                    status = AJ_UnmarshalArgs(msg, "(qqq)", &widget->property.val.date.mDay, &widget->property.val.date.month, &widget->property.val.date.fullYear);
                }
                /*
                 * Signal that the value has been changed
                 */
                AJS_CPS_SignalValueChanged(AJS_GetBusAttachment(), widget);
                if (status == AJ_OK) {
                    status = AJ_UnmarshalCloseContainer(msg, &st);
                }
            }
            break;
        }
    } else {
        return AJ_ERR_RESOURCES;
    }
    /*
     * Need to make a clone of the message and close the original
     */
    msg = AJS_CloneAndCloseMessage(widget->dukCtx, msg);
    if (!msg) {
        return AJ_ERR_RESOURCES;
    }
    if (status == AJ_OK) {
        /*
         * Call JavaScript to report the value change
         */
        status =  AJS_CPS_OnValueChanged(widget);
    } else {
        AJ_ErrPrintf(("SetWidgetProp %s\n", AJ_StatusText(status)));
    }
    if (status == AJ_OK) {
        AJ_MarshalReplyMsg(msg, &reply);
    } else {
        AJ_MarshalStatusMsg(msg, &reply, status);
    }
    AJ_DeliverMsg(&reply);

    return status;
}
static AJ_Status HandleMessage(duk_context* ctx, duk_idx_t ajIdx, AJ_Message* msg)
{
    duk_idx_t msgIdx;
    uint8_t accessor = AJS_NOT_ACCESSOR;
    const char* func;
    AJ_Status status;
    uint8_t ldstate;

#if !defined(AJS_CONSOLE_LOCKDOWN)
    status = AJS_GetLockdownState(&ldstate);
    if (status == AJ_OK && ldstate == AJS_CONSOLE_UNLOCKED) {
        status = AJS_ConsoleMsgHandler(ctx, msg);
        if (status != AJ_ERR_NO_MATCH) {
            if (status != AJ_OK) {
                AJ_WarnPrintf(("AJS_ConsoleMsgHandler returned %s\n", AJ_StatusText(status)));
            }
            return status;
        }
    }
#endif
    /*
     * JOIN_SESSION replies are handled in the AllJoyn.js layer and don't get passed to JavaScript
     */
    if (msg->msgId == AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION)) {
        return AJS_HandleJoinSessionReply(ctx, msg);
    }
    /*
     * Nothing more to do if the AllJoyn module was not loaded
     */
    if (ajIdx < 0) {
        return AJ_OK;
    }
    /*
     * Let the bases services layer take a look at the message
     */
    status = AJS_ServicesMsgHandler(msg);
    if (status != AJ_ERR_NO_MATCH) {
        if (status != AJ_OK) {
            AJ_WarnPrintf(("AJS_ServicesMsgHandler returned %s\n", AJ_StatusText(status)));
        }
        return status;
    }
    /*
     * Push the appropriate callback function onto the duktape stack
     */
    if (msg->hdr->msgType == AJ_MSG_SIGNAL) {
        /*
         * About announcements and found name signal get special handling
         */
        if (msg->msgId == AJ_SIGNAL_ABOUT_ANNOUNCE) {
            return AJS_AboutAnnouncement(ctx, msg);
        }
        if (msg->msgId == AJ_SIGNAL_FOUND_ADV_NAME) {
            return AJS_FoundAdvertisedName(ctx, msg);
        }
        if ((msg->msgId == AJ_SIGNAL_SESSION_LOST) || (msg->msgId == AJ_SIGNAL_SESSION_LOST_WITH_REASON)) {
            if (AJS_DebuggerIsAttached()) {
                msg = AJS_CloneAndCloseMessage(ctx, msg);
            }
            return AJS_SessionLost(ctx, msg);
        }
        func = "onSignal";
        duk_get_prop_string(ctx, ajIdx, func);
    } else if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) {
        accessor = IsPropAccessor(msg);
        switch (accessor) {
        case AJS_NOT_ACCESSOR:
            func = "onMethodCall";
            break;

        case AJ_PROP_GET:
            func = "onPropGet";
            break;

        case AJ_PROP_SET:
            func = "onPropSet";
            break;

        case AJ_PROP_GET_ALL:
            func = "onPropGetAll";
            break;

        default:
            return AJ_ERR_INVALID;
        }
        duk_get_prop_string(ctx, ajIdx, func);
    } else {
        func = "onReply";
        AJS_GetGlobalStashObject(ctx, func);
        if (duk_is_object(ctx, -1)) {
            duk_get_prop_index(ctx, -1, msg->replySerial);
            duk_swap_top(ctx, -2);
            /*
             * Clear the onReply entry
             */
            duk_del_prop_index(ctx, -1, msg->replySerial);
            duk_pop(ctx);
        }
    }
    /*
     * Skip if there is no function to call.
     */
    if (!duk_is_function(ctx, -1)) {
        if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) {
            AJ_Message error;
            AJ_WarnPrintf(("%s: not registered - rejecting message\n", func));
            AJ_MarshalErrorMsg(msg, &error, AJ_ErrRejected);
            status = AJ_DeliverMsg(&error);
        } else {
            AJ_WarnPrintf(("%s: not registered - ignoring message\n", func));
            status = AJ_OK;
        }
        duk_pop(ctx);
        return status;
    }
    /*
     * Opens up a stack entry above the function
     */
    duk_dup_top(ctx);
    msgIdx = AJS_UnmarshalMessage(ctx, msg, accessor);
    AJ_ASSERT(msgIdx == (ajIdx + 3));
    /*
     * Save the message object on the stack
     */
    duk_copy(ctx, msgIdx, -3);
    /*
     * Special case for GET prop so we can get the signature for marshalling the result
     */
    if (accessor == AJS_NOT_ACCESSOR) {
        status = AJS_UnmarshalMsgArgs(ctx, msg);
    } else {
        status = AJS_UnmarshalPropArgs(ctx, msg, accessor, msgIdx);
    }
    if (status == AJ_OK) {
        duk_idx_t numArgs = duk_get_top(ctx) - msgIdx - 1;
        /*
         * If attached, the debugger will begin to unmarshal a message when the
         * method handler is called, therefore it must be cloned-and-closed now.
         */
        if (AJS_DebuggerIsAttached()) {
            msg = AJS_CloneAndCloseMessage(ctx, msg);
        }
        if (duk_pcall_method(ctx, numArgs) != DUK_EXEC_SUCCESS) {
            const char* err = duk_safe_to_string(ctx, -1);

            AJ_ErrPrintf(("%s: %s\n", func, err));
            /*
             * Generate an error reply if this was a method call
             */
            if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) {
                duk_push_c_lightfunc(ctx, AJS_MethodCallError, 1, 0, 0);
                duk_insert(ctx, -3);
                (void)duk_pcall_method(ctx, 1);
            }
        }
    }
    /*
     * Cleanup stack back to the AJ object
     */
    duk_set_top(ctx, ajIdx + 1);
    return status;
}