To come on this changeset: All convergences between and server and client observation...
[platform/upstream/iotivity.git] / csdk / occoap / src / occoaphelper.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 //-----------------------------------------------------------------------------
22 // Includes
23 //-----------------------------------------------------------------------------
24 #include "occoaphelper.h"
25 #include "logger.h"
26
27 //-----------------------------------------------------------------------------
28 // Macros
29 //-----------------------------------------------------------------------------
30 #define TAG    PCF("OCCoAPHelper")
31 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
32
33 //=============================================================================
34 // Helper Functions
35 //=============================================================================
36
37 // Convert OCStack code to CoAP code
38 uint8_t OCToCoAPResponseCode(OCStackResult result)
39 {
40     uint8_t ret;
41     switch(result)
42     {
43         case OC_STACK_OK :
44             ret = COAP_RESPONSE_200;
45             break;
46
47         case OC_STACK_INVALID_QUERY :
48             ret = COAP_RESPONSE_400;
49             break;
50
51         case OC_STACK_NO_RESOURCE :
52             ret = COAP_RESPONSE_404;
53             break;
54
55         case OC_STACK_INVALID_METHOD :
56             ret = COAP_RESPONSE_405;
57             break;
58
59         default:
60             ret = COAP_RESPONSE_500;
61     }
62     return ret;
63 }
64
65
66 // Convert CoAP code to OCStack code
67 OCStackResult CoAPToOCResponseCode(uint8_t coapCode)
68 {
69     OCStackResult ret;
70     int decimal;
71     switch(coapCode)
72     {
73         case COAP_RESPONSE_200 :
74             ret = OC_STACK_OK;
75             break;
76
77         case COAP_RESPONSE_400 :
78             ret = OC_STACK_INVALID_QUERY;
79             break;
80
81         case COAP_RESPONSE_404 :
82             ret = OC_STACK_NO_RESOURCE;
83             break;
84
85         case COAP_RESPONSE_405 :
86             ret = OC_STACK_INVALID_METHOD;
87             break;
88
89         default:
90             decimal = ((coapCode >> 5) * 100) + (coapCode && 31);
91             if (decimal >= 200 && decimal <= 231)
92             {
93                 ret = OC_STACK_OK;
94             }
95             else
96             {
97                 ret = OC_STACK_ERROR;
98             }
99     }
100     return ret;
101 }
102
103
104 // Form the OCRequest struct
105 OCStackResult FormOCRequest(const coap_queue_t * rcvdRequest,
106         OCRequest * * requestLoc, unsigned char * uriBuf,
107         unsigned char * queryBuf) {
108
109     OCRequest * request = NULL;
110     OCObserveReq *obsReq = NULL;
111     size_t bufLen;
112     size_t optLen;
113     coap_opt_filter_t filter;
114     coap_opt_iterator_t opt_iter;
115     coap_opt_t *option;
116
117     // allocate it
118     request = (OCRequest *) OCMalloc(sizeof(OCRequest));
119     if (!request) {
120         return OC_STACK_NO_MEMORY;
121     }
122
123     // fill in qos
124     request->qos = OC_NON_CONFIRMABLE;
125     if (rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON) {
126         request->qos = OC_CONFIRMABLE;
127     }
128
129     // fill in uri
130     request->resourceUrl = NULL;
131     bufLen = 0;
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);
141             bufLen += optLen;
142         } else {
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;
146         }
147     }
148     uriBuf[bufLen] = '\0';
149     request->resourceUrl = uriBuf;
150
151     // fill in query
152     bufLen = 0;
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);
161             bufLen += optLen;
162             queryBuf[bufLen++] = '&';
163         } else {
164             // TODO: should it be OC_STACK_NO_MEMORY
165             return OC_STACK_INVALID_QUERY;
166         }
167     }
168     // delete last '&'
169     queryBuf[bufLen ? (bufLen - 1) : (bufLen)] = '\0';
170
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)
179         {
180             obsReq = request->observe;
181             obsReq->option = NULL;
182             obsReq->option = (unsigned char *)OCMalloc(COAP_OPT_LENGTH(option)+1);
183             if (obsReq->option)
184             {
185                 memcpy(obsReq->option, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
186                 (obsReq->option)[COAP_OPT_LENGTH(option)] = '\0';
187             }
188             else
189             {
190                 OCFree (request->observe);
191                 OCFree (request);
192                 return OC_STACK_NO_MEMORY;
193             }
194             obsReq->token = (OCCoAPToken *)OCMalloc(sizeof(MAX_TOKEN_LENGTH));
195             if(obsReq->token)
196             {
197                 memcpy (&obsReq->token->token, rcvdRequest->pdu->hdr->token, 
198                         rcvdRequest->pdu->hdr->token_length);
199                 obsReq->token->tokenLength = rcvdRequest->pdu->hdr->token_length;
200             }
201             else
202             {
203                 OCFree (request->observe);
204                 OCFree (request);
205                 return OC_STACK_NO_MEMORY;
206             }
207             obsReq->subAddr = (OCDevAddr *)&(rcvdRequest->remote);
208         } else {
209             OCFree (request);
210             return OC_STACK_NO_MEMORY;
211         }
212     }
213     OC_LOG_V(INFO, TAG, "Observe option %d", request->observe);
214
215     *requestLoc = request;
216     return OC_STACK_OK;
217 }
218
219 // Form the OCEntityHandlerRequest struct
220 OCStackResult FormOCEntityHandlerRequest(const coap_queue_t * rcvdRequest,
221         OCEntityHandlerRequest * * entityHandlerRequestLoc,
222         unsigned char * resBuf, unsigned char * query)
223 {
224     OCEntityHandlerRequest * entityHandlerRequest = NULL;
225     unsigned char * pReq = NULL;
226     size_t bufLen = 0;
227
228     entityHandlerRequest = (OCEntityHandlerRequest *) OCMalloc(
229             sizeof(OCEntityHandlerRequest));
230     if (!entityHandlerRequest)
231     {
232         return OC_STACK_NO_MEMORY;
233     }
234
235     entityHandlerRequest->method = (rcvdRequest->pdu->hdr->code == COAP_REQUEST_GET) ?
236             OC_REST_GET : OC_REST_PUT;
237
238     entityHandlerRequest->query = query;
239     coap_get_data(rcvdRequest->pdu, &bufLen, &pReq);
240     entityHandlerRequest->reqJSONPayload = pReq;
241
242     entityHandlerRequest->resJSONPayload = resBuf;
243     entityHandlerRequest->resJSONPayloadLen = MAX_RESPONSE_LENGTH;
244
245     *entityHandlerRequestLoc = entityHandlerRequest;
246     return OC_STACK_OK;
247 }
248
249 // Retrieve the token from the PDU
250 OCStackResult RetrieveOCCoAPToken(const coap_queue_t * rcvdRequest,
251         OCCoAPToken * * rcvdTokenLoc) {
252     OCCoAPToken * rcvdToken = NULL;
253
254     rcvdToken = (OCCoAPToken *) OCMalloc(sizeof(OCCoAPToken));
255     if (!rcvdToken) {
256         return OC_STACK_NO_MEMORY;
257     }
258     rcvdToken->tokenLength = rcvdRequest->pdu->hdr->token_length;
259     memcpy(rcvdToken->token, rcvdRequest->pdu->hdr->token,
260             rcvdToken->tokenLength);
261
262     *rcvdTokenLoc = rcvdToken;
263     return OC_STACK_OK;
264 }
265
266 OCStackResult FormOCResponse(const coap_queue_t * rcvdResponse,
267         OCResponse * * responseLoc) {
268     OCResponse * response = (OCResponse *) OCMalloc(sizeof(OCResponse));
269     if (!response) {
270         return OC_STACK_NO_MEMORY;
271     }
272     *responseLoc = response;
273     return OC_STACK_OK;
274 }
275
276 OCStackResult FormOCClientResponse(const coap_queue_t * rcvdResponse,
277         OCClientResponse * * clientResponseLoc) {
278
279     coap_opt_filter_t filter;
280     coap_opt_iterator_t opt_iter;
281     coap_opt_t *option;
282     unsigned char * pRes = NULL;
283     size_t bufLen = 0;
284
285     OCClientResponse * clientResponse = (OCClientResponse *) OCMalloc(
286             sizeof(OCClientResponse));
287     if (!clientResponse) {
288         return OC_STACK_NO_MEMORY;
289     }
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))) {
298         if (option)
299         {
300             memcpy(&clientResponse->sequenceNumber, COAP_OPT_VALUE(option),COAP_OPT_LENGTH(option));
301         }
302         else
303         {
304             return OC_STACK_NO_MEMORY;
305         }
306     }
307
308     coap_get_data(rcvdResponse->pdu, &bufLen, &pRes);
309     clientResponse->resJSONPayload = pRes;
310
311     *clientResponseLoc = clientResponse;
312     return OC_STACK_OK;
313 }
314
315 //generate a coap message
316 coap_pdu_t *
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) {
320     coap_pdu_t *pdu;
321     coap_list_t *opt;
322
323     pdu = coap_pdu_init(msgType, code, id, COAP_MAX_PDU_SIZE);
324     VERIFY_NON_NULL(pdu);
325
326     pdu->hdr->token_length = tokenLength;
327     if (!coap_add_token(pdu, tokenLength, token)) {
328         OC_LOG(FATAL, TAG, "coap_add_token failed");
329     }
330
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));
335     }
336
337     if (payloadJSON) {
338         coap_add_data(pdu, strlen((const char *) payloadJSON) + 1,
339                 (unsigned char*) payloadJSON);
340     }
341
342     // display the pdu for debugging purposes
343     coap_show_pdu(pdu);
344
345     return pdu;
346
347     exit: return NULL;
348 }
349
350 //a function to help in ordering coap options
351 int OrderOptions(void *a, void *b) {
352     if (!a || !b) {
353         return a < b ? -1 : 1;
354     }
355
356     if (COAP_OPTION_KEY(*(coap_option *)a)
357             < COAP_OPTION_KEY(*(coap_option *)b) ) {
358         return -1;
359     }
360
361     return COAP_OPTION_KEY(*(coap_option *)a)
362             == COAP_OPTION_KEY(*(coap_option *)b) ;
363 }
364
365 //a function to create a coap option
366 coap_list_t *
367 CreateNewOptionNode(unsigned short key, unsigned int length, unsigned char *data)
368 {
369     coap_option *option = NULL;
370     coap_list_t *node;
371
372     VERIFY_NON_NULL(data);
373     option = coap_malloc(sizeof(coap_option) + length);
374     VERIFY_NON_NULL(option);
375
376     COAP_OPTION_KEY(*option) = key;
377     COAP_OPTION_LENGTH(*option) = length;
378     memcpy(COAP_OPTION_DATA(*option), data, length);
379
380     /* we can pass NULL here as delete function since option is released automatically  */
381     node = coap_new_listnode(option, NULL);
382
383     if (node)
384     {
385         return node;
386     }
387
388 exit:
389     OC_LOG(ERROR,TAG,"new_option_node: malloc: was not created");
390     coap_free(option);
391     return NULL;
392 }