Commit 4db15af7 authored by Kishen Maloor's avatar Kishen Maloor

APIs to read/write raw request/response payloads

While the new APIs allow applications to send/receive raw payloads
of a specified content type from/to Servers/Clients, the stack is
currently lacking the following functionalities:

-Ability to transport raw payloads of a large size in a block-wise transfer.
-Ability to send raw payloads in asynchronous notifications.
-Ability to send raw payloads in separate responses.
-Ability to issue requests eliciting responses of a specific content type
(i.e. besides the default, CBOR).
Signed-off-by: Kishen Maloor's avatarKishen Maloor <kishen.maloor@intel.com>
parent 083923b8
......@@ -197,6 +197,23 @@ oc_free_server_endpoints(oc_endpoint_t *endpoint)
}
}
bool
oc_get_response_payload_raw(oc_client_response_t *response,
const uint8_t **payload, size_t *size,
oc_content_format_t *content_format)
{
if (!response || !payload || !size || !content_format) {
return false;
}
if (response->_payload && response->_payload_len > 0) {
*content_format = response->content_format;
*payload = response->_payload;
*size = response->_payload_len;
return true;
}
return false;
}
bool
oc_do_delete(const char *uri, oc_endpoint_t *endpoint, const char *query,
oc_response_handler_t handler, oc_qos_t qos, void *user_data)
......
......@@ -917,7 +917,7 @@ oc_handle_collection_request(oc_method_t method, oc_request_t *request,
break;
}
}
request->response->content_format = APPLICATION_VND_OCF_CBOR;
request->response->response_buffer->response_length = (uint16_t)size;
request->response->response_buffer->code = code;
......
......@@ -447,7 +447,7 @@ oc_core_1_1_discovery_handler(oc_request_t *request,
}
int response_length = oc_rep_get_encoded_payload_size();
request->response->content_format = APPLICATION_CBOR;
if (matches && response_length) {
request->response->response_buffer->response_length =
(uint16_t)response_length;
......@@ -500,6 +500,7 @@ oc_core_discovery_handler(oc_request_t *request, oc_interface_mask_t iface_mask,
break;
}
int response_length = oc_rep_get_encoded_payload_size();
request->response->content_format = APPLICATION_VND_OCF_CBOR;
if (matches && response_length > 0) {
request->response->response_buffer->response_length =
(uint16_t)response_length;
......
......@@ -78,7 +78,7 @@ oc_core_introspection_data_handler(oc_request_t *request,
IDD_size = oc_storage_read(
idd_tag, request->response->response_buffer->buffer, OC_MAX_APP_DATA_SIZE);
#endif /* OC_IDD_API */
request->response->content_format = APPLICATION_VND_OCF_CBOR;
if (IDD_size >= 0 && IDD_size < OC_MAX_APP_DATA_SIZE) {
request->response->response_buffer->response_length = (uint16_t)IDD_size;
request->response->response_buffer->code = oc_status_code(OC_STATUS_OK);
......
......@@ -675,6 +675,7 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
response_obj.separate_response = NULL;
response_obj.response_buffer = &response_buffer;
response_obj.content_format = 0;
request_obj.response = &response_obj;
request_obj.request_payload = NULL;
......@@ -682,6 +683,8 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
request_obj.query_len = 0;
request_obj.resource = NULL;
request_obj.origin = endpoint;
request_obj._payload = NULL;
request_obj._payload_len = 0;
/* Initialize OCF interface selector. */
oc_interface_mask_t iface_query = 0, iface_mask = 0;
......@@ -694,6 +697,10 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
const char *uri_query = 0;
size_t uri_query_len = coap_get_header_uri_query(request, &uri_query);
/* Read the Content-Format CoAP option in the request */
oc_content_format_t cf = 0;
coap_get_header_content_format(request, &cf);
if (uri_query_len) {
request_obj.query = uri_query;
request_obj.query_len = (int)uri_query_len;
......@@ -718,7 +725,9 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
#else /* OC_BLOCK_WISE */
payload_len = coap_get_payload(request, &payload);
#endif /* !OC_BLOCK_WISE */
request_obj._payload = payload;
request_obj._payload_len = (size_t)payload_len;
request_obj.content_format = cf;
#ifndef OC_DYNAMIC_ALLOCATION
char rep_objects_alloc[OC_MAX_NUM_REP_OBJECTS];
oc_rep_t rep_objects_pool[OC_MAX_NUM_REP_OBJECTS];
......@@ -732,7 +741,8 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
#endif /* OC_DYNAMIC_ALLOCATION */
oc_rep_set_pool(&rep_objects);
if (payload_len > 0) {
if (payload_len > 0 &&
(cf == APPLICATION_CBOR || cf == APPLICATION_VND_OCF_CBOR)) {
/* Attempt to parse request payload using tinyCBOR via oc_rep helper
* functions. The result of this parse is a tree of oc_rep_t structures
* which will reflect the schema of the payload.
......@@ -888,7 +898,7 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
}
}
if (payload_len) {
if (request_obj.request_payload) {
/* To the extent that the request payload was parsed, free the
* payload structure (and return its memory to the pool).
*/
......@@ -1100,13 +1110,8 @@ oc_ri_invoke_coap_entity_handler(void *request, void *response, uint8_t *buffer,
coap_set_payload(response, response_buffer.buffer,
response_buffer.response_length);
#endif /* !OC_BLOCK_WISE */
#ifdef OC_SPEC_VER_OIC
if (endpoint->version == OIC_VER_1_1_0) {
coap_set_header_content_format(response, APPLICATION_CBOR);
} else
#endif /* OC_SPEC_VER_OIC */
{
coap_set_header_content_format(response, APPLICATION_VND_OCF_CBOR);
if (response_obj.content_format > 0) {
coap_set_header_content_format(response, response_obj.content_format);
}
}
......@@ -1155,7 +1160,6 @@ notify_client_cb_503(oc_client_cb_t *cb)
client_response.client_cb = cb;
client_response.endpoint = &cb->endpoint;
client_response.observe_option = -1;
client_response.payload = 0;
client_response.user_data = cb->user_data;
client_response.code = OC_STATUS_SERVICE_UNAVAILABLE;
......@@ -1254,12 +1258,11 @@ oc_ri_invoke_client_cb(void *response, oc_client_cb_t *cb,
#endif /* OC_BLOCK_WISE */
{
endpoint->version = OCF_VER_1_0_0;
oc_content_format_t cf = 0;
coap_get_header_content_format(response, &cf);
#ifdef OC_SPEC_VER_OIC
unsigned int cf = 0;
if (coap_get_header_content_format(response, &cf) == 1) {
if (cf == APPLICATION_CBOR) {
endpoint->version = OIC_VER_1_1_0;
}
if (cf == APPLICATION_CBOR) {
endpoint->version = OIC_VER_1_1_0;
}
#endif /* OC_SPEC_VER_OIC */
......@@ -1276,6 +1279,9 @@ oc_ri_invoke_client_cb(void *response, oc_client_cb_t *cb,
client_response.endpoint = endpoint;
client_response.observe_option = -1;
client_response.payload = 0;
client_response._payload = 0;
client_response._payload_len = 0;
client_response.content_format = cf;
client_response.user_data = cb->user_data;
for (i = 0; i < __NUM_OC_STATUS_CODES__; i++) {
if (oc_coap_status_codes[i] == pkt->code) {
......@@ -1304,7 +1310,8 @@ oc_ri_invoke_client_cb(void *response, oc_client_cb_t *cb,
#else /* OC_BLOCK_WISE */
payload_len = coap_get_payload(response, (const uint8_t **)&payload);
#endif /* !OC_BLOCK_WISE */
client_response._payload = payload;
client_response._payload_len = (size_t)payload_len;
#ifndef OC_DYNAMIC_ALLOCATION
char rep_objects_alloc[OC_MAX_NUM_REP_OBJECTS];
oc_rep_t rep_objects_pool[OC_MAX_NUM_REP_OBJECTS];
......@@ -1331,7 +1338,13 @@ oc_ri_invoke_client_cb(void *response, oc_client_cb_t *cb,
return true;
}
} else {
int err = oc_parse_rep(payload, payload_len, &client_response.payload);
int err = 0;
/* Do not parse an incoming payload when the Content-Format option
* has not been set to the CBOR encoding.
*/
if (cf == APPLICATION_CBOR || cf == APPLICATION_VND_OCF_CBOR) {
err = oc_parse_rep(payload, payload_len, &client_response.payload);
}
if (err == 0) {
oc_response_handler_t handler =
(oc_response_handler_t)cb->handler.response;
......@@ -1339,7 +1352,9 @@ oc_ri_invoke_client_cb(void *response, oc_client_cb_t *cb,
} else {
OC_WRN("Error parsing payload!");
}
oc_free_rep(client_response.payload);
if (client_response.payload) {
oc_free_rep(client_response.payload);
}
}
} else {
if (pkt->type == COAP_TYPE_ACK && pkt->code == 0) {
......
......@@ -73,6 +73,14 @@ response_length(void)
void
oc_send_response(oc_request_t *request, oc_status_t response_code)
{
#ifdef OC_SPEC_VER_OIC
if (request->origin->version == OIC_VER_1_1_0) {
request->response->content_format = APPLICATION_CBOR;
} else
#endif /* OC_SPEC_VER_OIC */
{
request->response->content_format = APPLICATION_VND_OCF_CBOR;
}
request->response->response_buffer->response_length =
(uint16_t)response_length();
request->response->response_buffer->code = oc_status_code(response_code);
......@@ -167,6 +175,33 @@ more_or_done:
#ifdef OC_SERVER
bool
oc_get_request_payload_raw(oc_request_t *request, const uint8_t **payload,
size_t *size, oc_content_format_t *content_format)
{
if (!request || !payload || !size || !content_format) {
return false;
}
if (request->_payload && request->_payload_len > 0) {
*content_format = request->content_format;
*payload = request->_payload;
*size = request->_payload_len;
return true;
}
return false;
}
void
oc_send_response_raw(oc_request_t *request, const uint8_t *payload, size_t size,
oc_content_format_t content_format,
oc_status_t response_code)
{
request->response->content_format = content_format;
memcpy(request->response->response_buffer->buffer, payload, size);
request->response->response_buffer->response_length = (uint16_t)size;
request->response->response_buffer->code = oc_status_code(response_code);
}
static void
oc_populate_resource_object(oc_resource_t *resource, const char *name,
const char *uri, uint8_t num_resource_types,
......
......@@ -1296,6 +1296,16 @@ int oc_get_query_value(oc_request_t *request, const char *key, char **value);
*/
void oc_send_response(oc_request_t *request, oc_status_t response_code);
bool oc_get_request_payload_raw(oc_request_t *request, const uint8_t **payload,
size_t *size,
oc_content_format_t *content_format);
void oc_send_response_raw(oc_request_t *request, const uint8_t *payload,
size_t size, oc_content_format_t content_format,
oc_status_t response_code);
bool oc_get_response_payload_raw(oc_client_response_t *response,
const uint8_t **payload, size_t *size,
oc_content_format_t *content_format);
/**
* Ignore the request
*
......@@ -1755,10 +1765,11 @@ bool oc_init_post(const char *uri, oc_endpoint_t *endpoint, const char *query,
bool oc_do_post(void);
/**
* Dispatch a GET request with the CoAP Observe option to subscribe for notifications
* from a resource.
* Dispatch a GET request with the CoAP Observe option to subscribe for
* notifications from a resource.
*
* The oc_response_handler_t will be invoked each time upon receiving a notification.
* The oc_response_handler_t will be invoked each time upon receiving a
* notification.
*
* The handler will continue to be invoked till oc_stop_observe() is called.
*
......
......@@ -36,9 +36,12 @@ typedef enum { HIGH_QOS = 0, LOW_QOS } oc_qos_t;
typedef struct
{
oc_rep_t *payload;
const uint8_t *_payload;
size_t _payload_len;
oc_endpoint_t *endpoint;
void *client_cb;
void *user_data;
oc_content_format_t content_format;
oc_status_t code;
int observe_option;
} oc_client_response_t;
......
......@@ -26,8 +26,7 @@
#include "util/oc_etimer.h"
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
typedef enum { OC_GET = 1, OC_POST, OC_PUT, OC_DELETE } oc_method_t;
......@@ -65,6 +64,34 @@ typedef enum {
OC_PING_TIMEOUT
} oc_status_t;
/* OCF payload Content-Formats */
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1,
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40,
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_FASTINFOSET = 48,
APPLICATION_SOAP_FASTINFOSET = 49,
APPLICATION_JSON = 50,
APPLICATION_X_OBIX_BINARY = 51,
APPLICATION_CBOR = 60,
APPLICATION_VND_OCF_CBOR = 10000
} oc_content_format_t;
typedef struct oc_separate_response_s oc_separate_response_t;
typedef struct oc_response_buffer_s oc_response_buffer_t;
......@@ -73,6 +100,7 @@ typedef struct oc_response_t
{
oc_separate_response_t *separate_response;
oc_response_buffer_t *response_buffer;
oc_content_format_t content_format;
} oc_response_t;
typedef enum {
......@@ -130,6 +158,9 @@ typedef struct oc_request_t
const char *query;
size_t query_len;
oc_rep_t *request_payload;
const uint8_t *_payload;
size_t _payload_len;
oc_content_format_t content_format;
oc_response_t *response;
} oc_request_t;
......
......@@ -54,7 +54,7 @@
#ifdef OC_TCP
#include "coap_signal.h"
#endif /* OC_TCP */
#include "oc_ri.h"
#ifdef OC_SECURITY
#include "security/oc_tls.h"
#endif
......
......@@ -45,13 +45,11 @@
* This file is part of the Contiki operating system.
*/
#ifndef CONSTANTS_H
#define CONSTANTS_H
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#define COAP_DEFAULT_PORT 5683
......@@ -91,7 +89,9 @@ extern "C"
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F
#define COAP_TCP_DEFAULT_HEADER_LEN 2 /* | len:0xF0 tkl:0x0F | .... | code | */
#define COAP_TCP_DEFAULT_HEADER_LEN \
2 /* | len:0xF0 tkl:0x0F | .... | code | \
*/
#define COAP_TCP_MAX_EXTENDED_LENGTH_LEN 4
#define COAP_PAYLOAD_MARKER_LEN 1 /* 0xFF */
......@@ -180,34 +180,6 @@ typedef enum {
OCF_OPTION_CONTENT_FORMAT_VER = 2053 /* 2 B */
} coap_option_t;
/* CoAP Content-Formats */
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1,
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40,
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_FASTINFOSET = 48,
APPLICATION_SOAP_FASTINFOSET = 49,
APPLICATION_JSON = 50,
APPLICATION_X_OBIX_BINARY = 51,
APPLICATION_CBOR = 60,
APPLICATION_VND_OCF_CBOR = 10000
} coap_content_format_t;
#ifdef __cplusplus
}
#endif
......
......@@ -77,7 +77,7 @@ extern bool oc_ri_invoke_coap_entity_handler(
void *request, void *response, oc_blockwise_state_t **request_state,
oc_blockwise_state_t **response_state, uint16_t block2_size,
oc_endpoint_t *endpoint);
#else /* OC_BLOCK_WISE */
#else /* OC_BLOCK_WISE */
extern bool oc_ri_invoke_coap_entity_handler(void *request, void *response,
uint8_t *buffer,
oc_endpoint_t *endpoint);
......@@ -496,7 +496,7 @@ coap_receive(oc_message_t *msg)
if (oc_ri_invoke_coap_entity_handler(message, response, &request_buffer,
&response_buffer, block2_size,
&msg->endpoint)) {
#else /* OC_BLOCK_WISE */
#else /* OC_BLOCK_WISE */
if (oc_ri_invoke_coap_entity_handler(message, response,
transaction->message->data +
COAP_MAX_HEADER_SIZE,
......@@ -675,7 +675,7 @@ coap_receive(oc_message_t *msg)
message->token, message->token_len);
}
}
if (!error_response && response_buffer) {
if (response_buffer) {
OC_DBG("got response buffer for uri %s",
oc_string(response_buffer->href));
client_cb = (oc_client_cb_t *)response_buffer->client_cb;
......
......@@ -711,33 +711,31 @@ coap_notify_observers(oc_resource_t *resource,
continue;
}
if (response.separate_response != NULL) {
if (response_buf->code == oc_status_code(OC_STATUS_OK)) {
coap_packet_t req[1];
coap_packet_t req[1];
#ifdef OC_TCP
if (obs->endpoint.flags & TCP) {
coap_tcp_init_message(req, COAP_GET);
} else
if (obs->endpoint.flags & TCP) {
coap_tcp_init_message(req, COAP_GET);
} else
#endif /* OC_TCP */
{
coap_udp_init_message(req, COAP_TYPE_NON, COAP_GET, 0);
}
memcpy(req->token, obs->token, obs->token_len);
req->token_len = obs->token_len;
{
coap_udp_init_message(req, COAP_TYPE_NON, COAP_GET, 0);
}
memcpy(req->token, obs->token, obs->token_len);
req->token_len = obs->token_len;
coap_set_header_uri_path(req, oc_string(resource->uri),
oc_string_len(resource->uri));
coap_set_header_uri_path(req, oc_string(resource->uri),
oc_string_len(resource->uri));
OC_DBG("coap_notify_observers: Creating separate response for "
"notification");
OC_DBG("coap_notify_observers: Creating separate response for "
"notification");
#ifdef OC_BLOCK_WISE
if (coap_separate_accept(req, response.separate_response,
&obs->endpoint, 0, obs->block2_size) == 1)
if (coap_separate_accept(req, response.separate_response,
&obs->endpoint, 0, obs->block2_size) == 1)
#else /* OC_BLOCK_WISE */
if (coap_separate_accept(req, response.separate_response,
&obs->endpoint, 0) == 1)
if (coap_separate_accept(req, response.separate_response,
&obs->endpoint, 0) == 1)
#endif /* !OC_BLOCK_WISE */
response.separate_response->active = 1;
}
response.separate_response->active = 1;
} // separate response
else {
OC_DBG("coap_notify_observers: notifying observer");
......@@ -825,14 +823,9 @@ coap_notify_observers(oc_resource_t *resource,
} else {
coap_set_header_observe(notification, 1);
}
#ifdef OC_SPEC_VER_OIC
if (obs->endpoint.version == OIC_VER_1_1_0) {
coap_set_header_content_format(notification, APPLICATION_CBOR);
} else
#endif /* OC_SPEC_VER_OIC */
{
if (response.content_format > 0) {
coap_set_header_content_format(notification,
APPLICATION_VND_OCF_CBOR);
response.content_format);
}
coap_set_token(notification, obs->token, obs->token_len);
transaction = coap_new_transaction(coap_get_mid(), &obs->endpoint);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment