1 //******************************************************************
3 // Copyright 2014 Intel Corporation All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 //-----------------------------------------------------------------------------
23 //-----------------------------------------------------------------------------
24 #include "occoaphelper.h"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
30 #define TAG PCF("OCCoAPHelper")
31 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
33 //=============================================================================
35 //=============================================================================
37 // Convert OCStack code to CoAP code
38 uint8_t OCToCoAPResponseCode(OCStackResult result)
44 ret = COAP_RESPONSE_200;
47 case OC_STACK_INVALID_QUERY :
48 ret = COAP_RESPONSE_400;
51 case OC_STACK_NO_RESOURCE :
52 ret = COAP_RESPONSE_404;
55 case OC_STACK_INVALID_METHOD :
56 ret = COAP_RESPONSE_405;
60 ret = COAP_RESPONSE_500;
66 // Convert CoAP code to OCStack code
67 OCStackResult CoAPToOCResponseCode(uint8_t coapCode)
73 case COAP_RESPONSE_200 :
77 case COAP_RESPONSE_400 :
78 ret = OC_STACK_INVALID_QUERY;
81 case COAP_RESPONSE_404 :
82 ret = OC_STACK_NO_RESOURCE;
85 case COAP_RESPONSE_405 :
86 ret = OC_STACK_INVALID_METHOD;
90 decimal = ((coapCode >> 5) * 100) + (coapCode && 31);
91 if (decimal >= 200 && decimal <= 231)
104 // Form the OCRequest struct
105 OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
106 OCRequest * * requestLoc, unsigned char * uriBuf,
107 unsigned char * queryBuf) {
109 OCRequest * request = NULL;
110 OCObserveReq *obsReq = NULL;
113 coap_opt_filter_t filter;
114 coap_opt_iterator_t opt_iter;
118 request = (OCRequest *) OCMalloc(sizeof(OCRequest));
120 return OC_STACK_NO_MEMORY;
124 request->qos = OC_NON_CONFIRMABLE;
125 if (rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON) {
126 request->qos = OC_CONFIRMABLE;
130 request->resourceUrl = NULL;
132 coap_option_filter_clear(filter);
133 coap_option_setb(filter, COAP_OPTION_URI_PATH);
134 coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter);
135 while ((option = coap_option_next(&opt_iter))) {
136 optLen = COAP_OPT_LENGTH(option);
137 if (bufLen + 1 + optLen < MAX_URI_LENGTH) {
138 //we still have room in the buffer
139 uriBuf[bufLen++] = '/';
140 memcpy(uriBuf + bufLen, COAP_OPT_VALUE(option), optLen);
143 // TODO: should it be OC_STACK_NO_MEMORY
144 // TODO: we should check that resources do not have long uri at the registration
145 return OC_STACK_INVALID_URI;
148 uriBuf[bufLen] = '\0';
149 request->resourceUrl = uriBuf;
153 coap_option_filter_clear(filter);
154 coap_option_setb(filter, COAP_OPTION_URI_QUERY);
155 coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter);
156 while ((option = coap_option_next(&opt_iter))) {
157 optLen = COAP_OPT_LENGTH(option);
158 if (bufLen + 1 + optLen < MAX_QUERY_LENGTH) {
159 //we still have room in the buffer
160 memcpy(queryBuf + bufLen, COAP_OPT_VALUE(option), optLen);
162 queryBuf[bufLen++] = '&';
164 // TODO: should it be OC_STACK_NO_MEMORY
165 return OC_STACK_INVALID_QUERY;
169 queryBuf[bufLen ? (bufLen - 1) : (bufLen)] = '\0';
171 // fill in observe, if present
172 request->observe = NULL;
173 coap_option_filter_clear(filter);
174 coap_option_setb(filter, COAP_OPTION_OBSERVE);
175 coap_option_iterator_init(rcvdRequest->pdu, &opt_iter, filter);
176 while ((option = coap_option_next(&opt_iter))) {
177 request->observe = (OCObserveReq *)OCMalloc(sizeof(OCObserveReq));
178 if (request->observe)
180 obsReq = request->observe;
181 obsReq->option = NULL;
182 obsReq->option = (unsigned char *)OCMalloc(COAP_OPT_LENGTH(option)+1);
185 memcpy(obsReq->option, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
186 (obsReq->option)[COAP_OPT_LENGTH(option)] = '\0';
190 OCFree (request->observe);
192 return OC_STACK_NO_MEMORY;
194 obsReq->token = (OCCoAPToken *)OCMalloc(sizeof(MAX_TOKEN_LENGTH));
197 memcpy (&obsReq->token->token, rcvdRequest->pdu->hdr->token,
198 rcvdRequest->pdu->hdr->token_length);
199 obsReq->token->tokenLength = rcvdRequest->pdu->hdr->token_length;
203 OCFree (request->observe);
205 return OC_STACK_NO_MEMORY;
207 obsReq->subAddr = (OCDevAddr *)&(rcvdRequest->remote);
210 return OC_STACK_NO_MEMORY;
213 OC_LOG_V(INFO, TAG, "Observe option %d", request->observe);
215 *requestLoc = request;
219 // Form the OCEntityHandlerRequest struct
220 OCStackResult FormOCEntityHandlerRequest(const coap_queue_t * rcvdRequest,
221 OCEntityHandlerRequest * * entityHandlerRequestLoc,
222 unsigned char * resBuf, unsigned char * query)
224 OCEntityHandlerRequest * entityHandlerRequest = NULL;
225 unsigned char * pReq = NULL;
228 entityHandlerRequest = (OCEntityHandlerRequest *) OCMalloc(
229 sizeof(OCEntityHandlerRequest));
230 if (!entityHandlerRequest)
232 return OC_STACK_NO_MEMORY;
235 entityHandlerRequest->method = (rcvdRequest->pdu->hdr->code == COAP_REQUEST_GET) ?
236 OC_REST_GET : OC_REST_PUT;
238 entityHandlerRequest->query = query;
239 coap_get_data(rcvdRequest->pdu, &bufLen, &pReq);
240 entityHandlerRequest->reqJSONPayload = pReq;
242 entityHandlerRequest->resJSONPayload = resBuf;
243 entityHandlerRequest->resJSONPayloadLen = MAX_RESPONSE_LENGTH;
245 *entityHandlerRequestLoc = entityHandlerRequest;
249 // Retrieve the token from the PDU
250 OCStackResult RetrieveOCCoAPToken(const coap_queue_t * rcvdRequest,
251 OCCoAPToken * * rcvdTokenLoc) {
252 OCCoAPToken * rcvdToken = NULL;
254 rcvdToken = (OCCoAPToken *) OCMalloc(sizeof(OCCoAPToken));
256 return OC_STACK_NO_MEMORY;
258 rcvdToken->tokenLength = rcvdRequest->pdu->hdr->token_length;
259 memcpy(rcvdToken->token, rcvdRequest->pdu->hdr->token,
260 rcvdToken->tokenLength);
262 *rcvdTokenLoc = rcvdToken;
266 OCStackResult FormOCResponse(const coap_queue_t * rcvdResponse,
267 OCResponse * * responseLoc) {
268 OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse));
270 return OC_STACK_NO_MEMORY;
272 *responseLoc = response;
276 OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse,
277 OCClientResponse * * clientResponseLoc) {
279 coap_opt_filter_t filter;
280 coap_opt_iterator_t opt_iter;
282 unsigned char * pRes = NULL;
285 OCClientResponse * clientResponse = (OCClientResponse *) OCMalloc(
286 sizeof(OCClientResponse));
287 if (!clientResponse) {
288 return OC_STACK_NO_MEMORY;
290 clientResponse->sequenceNumber = 0;
291 clientResponse->result = OC_STACK_ERROR;
292 clientResponse->addr = (OCDevAddr *) &(rcvdResponse->remote);
293 // fill in observe, if present
294 coap_option_filter_clear(filter);
295 coap_option_setb(filter, COAP_OPTION_OBSERVE);
296 coap_option_iterator_init(rcvdResponse->pdu, &opt_iter, filter);
297 while ((option = coap_option_next(&opt_iter))) {
300 memcpy(&clientResponse->sequenceNumber, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
304 return OC_STACK_NO_MEMORY;
308 coap_get_data(rcvdResponse->pdu, &bufLen, &pRes);
309 clientResponse->resJSONPayload = pRes;
311 *clientResponseLoc = clientResponse;
315 //generate a coap message
317 GenerateCoAPPdu(uint8_t msgType, uint8_t code, unsigned short id,
318 size_t tokenLength, uint8_t * token, unsigned char * payloadJSON,
319 coap_list_t *options) {
323 pdu = coap_pdu_init(msgType, code, id, COAP_MAX_PDU_SIZE);
324 VERIFY_NON_NULL(pdu);
326 pdu->hdr->token_length = tokenLength;
327 if (!coap_add_token(pdu, tokenLength, token)) {
328 OC_LOG(FATAL, TAG, "coap_add_token failed");
331 for (opt = options; opt; opt = opt->next) {
332 coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
333 COAP_OPTION_LENGTH(*(coap_option *) opt->data),
334 COAP_OPTION_DATA(*(coap_option *) opt->data));
338 coap_add_data(pdu, strlen((const char *) payloadJSON) + 1,
339 (unsigned char*) payloadJSON);
342 // display the pdu for debugging purposes
350 //a function to help in ordering coap options
351 int OrderOptions(void *a, void *b) {
353 return a < b ? -1 : 1;
356 if (COAP_OPTION_KEY(*(coap_option *)a)
357 < COAP_OPTION_KEY(*(coap_option *)b) ) {
361 return COAP_OPTION_KEY(*(coap_option *)a)
362 == COAP_OPTION_KEY(*(coap_option *)b) ;
365 //a function to create a coap option
367 CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data)
369 coap_option *option = NULL;
372 VERIFY_NON_NULL(data);
373 option = coap_malloc(sizeof(coap_option) + length);
374 VERIFY_NON_NULL(option);
376 COAP_OPTION_KEY(*option) = key;
377 COAP_OPTION_LENGTH(*option) = length;
378 memcpy(COAP_OPTION_DATA(*option), data, length);
380 /* we can pass NULL here as delete function since option is released automatically */
381 node = coap_new_listnode(option, NULL);
389 OC_LOG(ERROR,TAG,"new_option_node: malloc: was not created");