User Tools

Site Tools


respond_from_request

Formatting Messages for Responding to Requests

Previously we have studied the Initialize & Setting to Request and Response parts. Now let's discover how to format messages.

Sample Application :

The simpleserver and simpleclient examples are a good place to learn about this subject:

C SDK

Messaging can be done with either the C or the C++ SD; the code is similar so only a couple of case are shown here.

Here are the relevant functions.

From iotivity/resource/csdk/stack/include/ocpayload.h:

  • OCRepPayloadCreate - Creates a new payload
  • OCRepPayloadSetProp* - Various functions used to set properties of a payload.
  • OCRepPayloadGetProp* - Various functions used to get properties of a payload.

From iotivity/resource/csdk/stack/include/ocstack.h:

  • OCDoResource (client) - Discovers or performs requests on a resource that's specified by a URI.
  • OCDoResponse (server) - Sends a response to a request.

Please refer to the CSDK API documentation for more information.

OCDoResponse & OCRepPayloadSetProp* (server)

OCDoResource and OCDoResponse were introduced in the section on communicating with resources. This section will use the same starting point to explain the process of creating and attaching payloads to responses.


typedef struct LIGHTRESOURCE
{
    OCResourceHandle handle;
    bool state;
} LightResource;

static LightResource Light;


OCEntityHandlerResult handleOCEntity(OCEntityHandlerFlag flag,
                                     OCEntityHandlerRequest *entityHandlerRequest,
                                     void *callbackParam)
{
    OCEntityHandlerResult result = OC_EH_OK;
    OCEntityHandlerResponse response = {0};

    OIC_LOG_V(INFO, TAG, "%s",__FUNCTION__);

    OCRepPayload *payload = (OCRepPayload *) OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
        return OC_EH_ERROR;
    }

    if (entityHandlerRequest && (flag & OC_REQUEST_FLAG))
    {
        OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");

        if (OC_REST_GET == entityHandlerRequest->method)
        {
            OCRepPayloadSetUri(payload, gUri);
            OCRepPayloadSetPropBool(payload, "state", Light.state);
            OCRepPayloadAddResourceType(payload, "core.light");
        }

        {
            // Format the response.  Note this requires some info about the request
            response.requestHandle = entityHandlerRequest->requestHandle;
            response.resourceHandle = entityHandlerRequest->resource;
            response.ehResult = result;
            response.payload = (OCPayload *) payload;
            response.numSendVendorSpecificHeaderOptions = 0;
            memset(response.sendVendorSpecificHeaderOptions, 0,
                   sizeof response.sendVendorSpecificHeaderOptions);
            memset(response.resourceUri, 0, sizeof response.resourceUri);
            // Indicates that response is NOT in a persistent buffer
            response.persistentBufferFlag = 0;

            // Send the response
            if (OCDoResponse(&response) != OC_STACK_OK)
            {
                OIC_LOG(ERROR, TAG, "Error sending response");
                result = OC_EH_ERROR;
            }
        }
    OCRepPayloadDestroy(payload);
    return result;
}

OCDoResource / OCRepPayloadGetProp* (client)

On the client side, the callback is modified to parse the payload. In this case, it reads the “state” field. This uses the OCRepPayloadGetProp* functions. (please note: extra checks are missing for this code snippet).

The following code makes a GET request to the resource without a payload attached.

OCStackResult get()
{
    OCStackResult result = OC_STACK_OK;
    OCMethod method = OC_REST_GET;
    OCCallbackData getCallback = { NULL, NULL, NULL };
    getCallback.cb = handleGet;
    OCRepPayload* payload = NULL;
    
    result = OCDoResource(&Light.handle, method, gUri, &gDestination,
                          (OCPayload*) payload,
                          gConnectivityType, gQos, &getCallback, NULL,0);

    return result;
}

On the server reply, the callback that was just passed will be invoked. Then, the payload can be parsed.

OCStackApplicationResult handleGet(void *ctx,
                                   OCDoHandle handle,
                                   OCClientResponse *clientResponse)
{

    OCStackApplicationResult result= OC_STACK_DELETE_TRANSACTION;
    if (!clientResponse)
    {
        return result;
    }    
    OCRepPayload* payload = (OCRepPayload*)(clientResponse->payload);
    if (!payload)
    {
        return result;
    }    

    if(OCRepPayloadGetPropBool(payload, "state", &Light.state))
    {
        printf("get: %d\n", Light.state);
    }

    return OC_STACK_DELETE_TRANSACTION;
}

C++ SDK

Here are the relevant methods.

From OC::OCRepresentation

  • OC::OCRepresentation::setValue - Set an attribute value with a supplied name.
  • OC::OCRepresentation::getValue - Retrieve an attribute value with a supplied name.
MyClass::MyClass(shared_ptr<OCResource> Resource)
{
    m_resourceHandle = Resource;
    m_GETCallback = bind(&MyClass::onGet, this, placeholders::_1, placeholders::_2, placeholders::_3);
    m_PUTCallback = bind(&MyClass::onPut, this, placeholders::_1, placeholders::_2, placeholders::_3);
}


void MyClass::get()
{
    QueryParamsMap params;
    m_resourceHandle->get(params, m_GETCallback);
}


void MyClass::handleGet(const HeaderOptions &headerOptions,
                        const OCRepresentation &representation,
                        int errCode)
{
    if (errCode == OC_STACK_OK)
    {
        bool value;
        representation.getValue("state", value);
    }
// ....
}

Next Steps

Once you've completed this section of the guide, the next section covers resource observation.

respond_from_request.txt · Last modified: 2017/03/28 21:09 by Ben Lloyd Pearson