Fixed crash on rec'd invalid data.
[platform/upstream/iotivity.git] / resource / csdk / occoap / src / occoap.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 //=============================================================================
23 // Includes
24 //=============================================================================
25 #define _POSIX_C_SOURCE 200112L
26 #include <string.h>
27 #include "occoap.h"
28 #include "ocstackconfig.h"
29 #include "occlientcb.h"
30 #include "ocobserve.h"
31 #include "logger.h"
32 #include "ocmalloc.h"
33 #include <coap.h>
34
35 #ifndef WITH_ARDUINO
36 #include <unistd.h>
37 #endif
38 #include <limits.h>
39 #include <ctype.h>
40
41 //=============================================================================
42 // Macros
43 //=============================================================================
44 #define TAG    PCF("OCCoAP")
45 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
46             {OC_LOG_V(FATAL, TAG, "%s failed!!", #op); goto exit;} }
47 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG_V(FATAL, TAG, "%s is NULL", #arg); goto exit;} }
48
49 //=============================================================================
50 // Defines
51 //=============================================================================
52 #define COAP_BLOCK_FILL_VALUE   (0xFF)
53
54 //=============================================================================
55 // Private Variables
56 //=============================================================================
57
58 static coap_context_t *gCoAPCtx = NULL;
59
60 //=============================================================================
61 // Helper Functions
62 //=============================================================================
63
64 //generate a coap token
65 void OCGenerateCoAPToken(OCCoAPToken * token)
66 {
67     if (token)
68     {
69         token->tokenLength = MAX_TOKEN_LENGTH;
70         OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
71     }
72 }
73
74 //This function is called back by libcoap when ack or rst are received
75 static void HandleCoAPAckRst(struct coap_context_t * ctx, uint8_t msgType,
76         const coap_queue_t * sentQueue){
77
78     // silence warnings
79     (void) ctx;
80     coap_pdu_t * sentPdu = sentQueue->pdu;
81     OCStackResult result = OC_STACK_ERROR;
82     uint32_t observationOption = OC_OBSERVE_NO_OPTION;
83     // {{0}} to eliminate warning for known compiler bug 53119
84     // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
85     OCCoAPToken sentToken = {{0}};
86
87     result = ParseCoAPPdu(sentPdu, NULL, NULL, &observationOption, NULL, NULL, NULL,
88             NULL, NULL, NULL, NULL, NULL);
89     VERIFY_SUCCESS(result, OC_STACK_OK);
90
91     // fill OCCoAPToken structure
92     RetrieveOCCoAPToken(sentPdu, &sentToken);
93
94     if(msgType == COAP_MESSAGE_RST)
95     {
96         if(myStackMode != OC_CLIENT)
97         {
98             result = OCStackFeedBack(&sentToken, OC_OBSERVER_NOT_INTERESTED);
99             if(result == OC_STACK_OK)
100             {
101                 OC_LOG_V(DEBUG, TAG,
102                         "Received RST, removing all queues associated with Token %d bytes",
103                         sentToken.tokenLength);
104                 OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
105                 coap_cancel_all_messages(ctx, &sentQueue->remote, sentToken.token,
106                         sentToken.tokenLength);
107             }
108         }
109     }
110     else if(observationOption != OC_OBSERVE_NO_OPTION && msgType == COAP_MESSAGE_ACK)
111     {
112         OC_LOG_V(DEBUG, TAG, "Received ACK, for Token %d bytes",sentToken.tokenLength);
113         OC_LOG_BUFFER(INFO, TAG, sentToken.token, sentToken.tokenLength);
114         // now the observer is still interested
115         if(myStackMode != OC_CLIENT)
116         {
117             OCStackFeedBack(&sentToken, OC_OBSERVER_STILL_INTERESTED);
118         }
119     }
120 exit:
121     return;
122 }
123
124 //This function is called back by libcoap when a request is received
125 static void HandleCoAPRequests(struct coap_context_t *ctx,
126         const coap_queue_t * rcvdRequest)
127 {
128     // silence warnings
129     (void) ctx;
130     OCServerProtocolRequest protocolRequest = {(OCMethod)0};
131     coap_block_t rcvdBlock1;
132     coap_block_t rcvdBlock2;
133     memset(&rcvdBlock1, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t));
134     memset(&rcvdBlock2, COAP_BLOCK_FILL_VALUE, sizeof(coap_block_t));
135     uint16_t rcvdSize1 = 0;
136     coap_pdu_t * rcvdPdu = rcvdRequest->pdu;
137     coap_pdu_t * sendPdu = NULL;
138     coap_send_flags_t sendFlag;
139     OCStackResult result = OC_STACK_ERROR;
140     OCStackResult requestResult = OC_STACK_ERROR;
141
142     if(myStackMode == OC_CLIENT)
143     {
144         //TODO: should the client be responding to requests?
145         return;
146     }
147
148     protocolRequest.observationOption = OC_OBSERVE_NO_OPTION;
149     protocolRequest.qos = (rcvdPdu->hdr->type == COAP_MESSAGE_CON) ?
150             OC_HIGH_QOS : OC_LOW_QOS;
151     protocolRequest.coapID = rcvdPdu->hdr->id;
152     protocolRequest.delayedResNeeded = rcvdRequest->delayedResNeeded;
153     protocolRequest.secured = rcvdRequest->secure;
154
155     // fill OCCoAPToken structure
156     RetrieveOCCoAPToken(rcvdPdu, &protocolRequest.requestToken);
157     OC_LOG_V(INFO, TAG, " Token received %d bytes",
158             protocolRequest.requestToken.tokenLength);
159     OC_LOG_BUFFER(INFO, TAG, protocolRequest.requestToken.token,
160             protocolRequest.requestToken.tokenLength);
161
162     // fill OCDevAddr
163     memcpy(&protocolRequest.requesterAddr, (OCDevAddr *) &rcvdRequest->remote,
164             sizeof(OCDevAddr));
165
166     // Retrieve Uri and Query from received coap pdu
167     result =  ParseCoAPPdu(rcvdPdu, protocolRequest.resourceUrl,
168             protocolRequest.query,
169             &(protocolRequest.observationOption), NULL,
170             &(protocolRequest.numRcvdVendorSpecificHeaderOptions),
171             protocolRequest.rcvdVendorSpecificHeaderOptions,
172             &rcvdBlock1, &rcvdBlock2, &rcvdSize1, NULL,
173             protocolRequest.reqJSONPayload);
174     VERIFY_SUCCESS(result, OC_STACK_OK);
175
176     switch (rcvdPdu->hdr->code)
177     {
178         case COAP_REQUEST_GET:
179         {
180             protocolRequest.method = OC_REST_GET;
181             break;
182         }
183         case COAP_REQUEST_POST:
184         {
185             protocolRequest.method = OC_REST_POST;
186             break;
187         }
188         case COAP_REQUEST_DELETE:
189         {
190             protocolRequest.method = OC_REST_DELETE;
191             break;
192         }
193         case COAP_REQUEST_PUT:
194         {
195             protocolRequest.method = OC_REST_PUT;
196             break;
197         }
198         default:
199         {
200             OC_LOG_V(ERROR, TAG, "Received CoAP method %d not supported",
201                     rcvdPdu->hdr->code);
202             goto exit;
203         }
204     }
205
206     if(rcvdBlock1.szx != 7)
207     {
208         protocolRequest.reqPacketSize = 1 << (rcvdBlock1.szx + 4);
209         protocolRequest.reqMorePacket = rcvdBlock1.m;
210         protocolRequest.reqPacketNum  = rcvdBlock1.num;
211     }
212     else
213     {
214         // No block1 received
215         rcvdSize1 = strlen((const char *)protocolRequest.reqJSONPayload)+1;
216         protocolRequest.reqTotalSize = rcvdSize1;
217     }
218
219     if(rcvdBlock2.szx != 7)
220     {
221         protocolRequest.resPacketSize = 1 << (rcvdBlock2.szx + 4);
222         protocolRequest.resPacketNum  = rcvdBlock2.num;
223     }
224
225     requestResult = HandleStackRequests(&protocolRequest);
226
227     if(requestResult == OC_STACK_VIRTUAL_DO_NOT_HANDLE ||
228             requestResult == OC_STACK_OK ||
229             requestResult == OC_STACK_RESOURCE_CREATED ||
230             requestResult == OC_STACK_RESOURCE_DELETED ||
231             requestResult == OC_STACK_INVALID_DEVICE_INFO)
232     {
233         goto exit;
234     }
235     else if(requestResult == OC_STACK_NO_MEMORY ||
236             requestResult == OC_STACK_ERROR ||
237             requestResult == OC_STACK_NOTIMPL ||
238             requestResult == OC_STACK_NO_RESOURCE ||
239             requestResult == OC_STACK_RESOURCE_ERROR)
240     {
241         // TODO: should we send an error also when we receive a non-secured request to a secure resource?
242         // TODO: should we consider some sort of error response
243         OC_LOG(DEBUG, TAG, PCF("We should send some sort of error message"));
244         // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
245         sendPdu = GenerateCoAPPdu((rcvdPdu->hdr->type == COAP_MESSAGE_CON)? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
246                 OCToCoAPResponseCode(requestResult), rcvdPdu->hdr->id,
247                 &protocolRequest.requestToken, NULL, NULL);
248         VERIFY_NON_NULL(sendPdu);
249         coap_show_pdu(sendPdu);
250         sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0);
251         if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
252                 sendFlag)
253                 != OC_STACK_OK){
254             OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
255         }
256         goto exit;
257     }
258     else if(requestResult == OC_STACK_SLOW_RESOURCE ||
259             requestResult == OC_STACK_REPEATED_REQUEST)
260     {
261         if(rcvdPdu->hdr->type == COAP_MESSAGE_CON)
262         {
263             // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
264             sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0, rcvdPdu->hdr->id,
265                     NULL, NULL, NULL);
266             VERIFY_NON_NULL(sendPdu);
267             coap_show_pdu(sendPdu);
268
269             sendFlag = (coap_send_flags_t)(rcvdRequest->secure ? SEND_SECURE_PORT : 0);
270             if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) &(rcvdRequest->remote), sendPdu,
271                     sendFlag)
272                     != OC_STACK_OK){
273                 OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
274             }
275         }
276         else
277         {
278             goto exit;
279         }
280     }
281 exit:
282     return;
283 }
284
285 uint32_t GetTime(float afterSeconds)
286 {
287     coap_tick_t now;
288     coap_ticks(&now);
289     return now + (uint32_t)(afterSeconds * COAP_TICKS_PER_SECOND);
290 }
291
292 //This function is called back by libcoap when a response is received
293 static void HandleCoAPResponses(struct coap_context_t *ctx,
294         const coap_queue_t * rcvdResponse) {
295     OCResponse * response = NULL;
296     OCCoAPToken rcvdToken;
297     OCClientResponse clientResponse = {0};
298     ClientCB * cbNode = NULL;
299     unsigned char bufRes[MAX_RESPONSE_LENGTH] = {0};
300     uint32_t sequenceNumber = OC_OBSERVE_NO_OPTION;
301     uint32_t maxAge = 0;
302     OCStackResult result = OC_STACK_ERROR;
303     coap_pdu_t * sendPdu = NULL;
304     coap_pdu_t * recvPdu = NULL;
305     unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
306     uint8_t isObserveNotification = 0;
307     #ifdef WITH_PRESENCE
308     char * resourceTypeName = NULL;
309     uint8_t remoteIpAddr[4];
310     uint16_t remotePortNu;
311     unsigned char fullUri[MAX_URI_LENGTH] = { 0 };
312     uint8_t isPresenceNotification = 0;
313     uint8_t isMulticastPresence = 0;
314     uint32_t lowerBound;
315     uint32_t higherBound;
316     char * tok = NULL;
317     #endif
318     coap_block_t rcvdBlock1 = {COAP_BLOCK_FILL_VALUE};
319     coap_block_t rcvdBlock2 = {COAP_BLOCK_FILL_VALUE};
320     uint16_t rcvdSize2 = 0;
321
322     VERIFY_NON_NULL(ctx);
323     VERIFY_NON_NULL(rcvdResponse);
324     recvPdu = rcvdResponse->pdu;
325
326     result = ParseCoAPPdu(recvPdu, rcvdUri, NULL, &sequenceNumber, &maxAge,
327             &clientResponse.numRcvdVendorSpecificHeaderOptions,
328             clientResponse.rcvdVendorSpecificHeaderOptions,
329             &rcvdBlock1, &rcvdBlock2, NULL, &rcvdSize2, bufRes);
330
331     VERIFY_SUCCESS(result, OC_STACK_OK);
332
333     OC_LOG_V(DEBUG, TAG, "The sequenceNumber/NONCE of this response %u", sequenceNumber);
334     OC_LOG_V(DEBUG, TAG, "The maxAge/TTL of this response %u", maxAge);
335     OC_LOG_V(DEBUG, TAG, "The response received is %s", bufRes);
336
337     if(sequenceNumber >= OC_OFFSET_SEQUENCE_NUMBER)
338     {
339         isObserveNotification = 1;
340         OC_LOG(INFO, TAG, PCF("Received an observe notification"));
341     }
342
343     #ifdef WITH_PRESENCE
344     if(!strcmp((char *)rcvdUri, (char *)OC_PRESENCE_URI)){
345         char* tokSavePtr;
346
347         isPresenceNotification = 1;
348         OC_LOG(INFO, TAG, PCF("Received a presence notification"));
349         tok = strtok_r((char *)bufRes, "[:]}", &tokSavePtr);
350         bufRes[strlen((char *)bufRes)] = ':';
351         tok = strtok_r(NULL, "[:]}", &tokSavePtr);
352         bufRes[strlen((char *)bufRes)] = ':';
353         VERIFY_NON_NULL(tok);
354         sequenceNumber = (uint32_t )atol(tok);
355         OC_LOG_V(DEBUG, TAG, "The received NONCE is %u", sequenceNumber);
356         tok = strtok_r(NULL, "[:]}", &tokSavePtr);
357         VERIFY_NON_NULL(tok);
358         maxAge = (uint32_t )atol(tok);
359         OC_LOG_V(DEBUG, TAG, "The received TTL is %u", maxAge);
360         tok = strtok_r(NULL, "[:]}", &tokSavePtr);
361         if(tok) {
362             bufRes[strlen((char *)bufRes)] = ':';
363             resourceTypeName = (char *)OCMalloc(strlen(tok));
364             if(!resourceTypeName)
365             {
366                 goto exit;
367             }
368             strcpy(resourceTypeName, tok);
369             OC_LOG_V(DEBUG, TAG, "----------------resourceTypeName %s",
370                     resourceTypeName);
371         }
372         bufRes[strlen((char *)bufRes)] = ']';
373     }
374     #endif
375
376     // fill OCCoAPToken structure
377     RetrieveOCCoAPToken(recvPdu, &rcvdToken);
378     OC_LOG_V(INFO, TAG,"Received a pdu with Token", rcvdToken.tokenLength);
379     OC_LOG_BUFFER(INFO, TAG, rcvdToken.token, rcvdToken.tokenLength);
380
381     // fill OCClientResponse structure
382     result = FormOCClientResponse(&clientResponse, CoAPToOCResponseCode(recvPdu->hdr->code),
383             (OCDevAddr *) &(rcvdResponse->remote), sequenceNumber, bufRes);
384     VERIFY_SUCCESS(result, OC_STACK_OK);
385
386     cbNode = GetClientCB(&rcvdToken, NULL, NULL);
387
388     #ifdef WITH_PRESENCE
389     // Check if the application subscribed for presence
390     if(!cbNode)
391     {
392         // get the address of the remote
393         OCDevAddrToIPv4Addr((OCDevAddr *) &(rcvdResponse->remote), remoteIpAddr,
394                 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
395         OCDevAddrToPort((OCDevAddr *) &(rcvdResponse->remote), &remotePortNu);
396         snprintf((char *)fullUri, sizeof(fullUri), "coap://%d.%d.%d.%d:%d%s",
397                 remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
398                 remotePortNu,rcvdUri);
399         cbNode = GetClientCB(NULL, NULL, fullUri);
400     }
401
402     // Check if application subscribed for multicast presence
403     if(!cbNode)
404     {
405         snprintf((char *)fullUri, sizeof(fullUri), "%s%s", OC_MULTICAST_IP, rcvdUri);
406         cbNode = GetClientCB(NULL, NULL, fullUri);
407         isMulticastPresence = 1;
408         isPresenceNotification = 0;
409     }
410     #endif
411
412     // fill OCResponse structure
413     result = FormOCResponse(&response, cbNode, maxAge, &clientResponse);
414     VERIFY_SUCCESS(result, OC_STACK_OK);
415
416     if(cbNode)
417     {
418         if(!isObserveNotification)
419         {
420             #ifdef WITH_PRESENCE
421             if(!isPresenceNotification)
422             {
423             #endif
424                 OC_LOG(INFO, TAG, PCF("Received a regular response"));
425                 if(recvPdu->hdr->type == COAP_MESSAGE_CON)
426                 {
427                     sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
428                             recvPdu->hdr->id, NULL, NULL, NULL);
429                     VERIFY_NON_NULL(sendPdu);
430                     result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
431                             sendPdu,
432                             (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
433                 }
434             #ifdef WITH_PRESENCE
435             }
436             #endif
437         }
438         if(isObserveNotification)
439         {
440             OC_LOG(INFO, TAG, PCF("Received an observe notification"));
441             if(recvPdu->hdr->type == COAP_MESSAGE_CON)
442             {
443                 sendPdu = GenerateCoAPPdu(COAP_MESSAGE_ACK, 0,
444                         recvPdu->hdr->id, NULL, NULL, NULL);
445                 VERIFY_NON_NULL(sendPdu);
446                 result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote,
447                         sendPdu,
448                         (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
449             }
450             //TODO: check the standard for methods to detect wrap around condition
451             if(cbNode->method == OC_REST_OBSERVE &&
452                     (clientResponse.sequenceNumber <= cbNode->sequenceNumber ||
453                             (clientResponse.sequenceNumber > cbNode->sequenceNumber &&
454                                     clientResponse.sequenceNumber == (MAX_SEQUENCE_NUMBER))))
455             {
456                 OC_LOG_V(DEBUG, TAG, "Observe notification came out of order. \
457                         Ignoring Incoming:%d  Against Current:%d.",
458                         clientResponse.sequenceNumber, cbNode->sequenceNumber);
459                 goto exit;
460             }
461             if(clientResponse.sequenceNumber > cbNode->sequenceNumber){
462                 cbNode->sequenceNumber = clientResponse.sequenceNumber;
463             }
464         }
465         else
466         {
467             #ifdef WITH_PRESENCE
468             if(isPresenceNotification)
469             {
470                 OC_LOG(INFO, TAG, PCF("Received a presence notification"));
471                 if(!cbNode->presence)
472                 {
473                     cbNode->presence = (OCPresence *) OCMalloc(sizeof(OCPresence));
474                     VERIFY_NON_NULL(cbNode->presence);
475                     cbNode->presence->timeOut = NULL;
476                     cbNode->presence->timeOut = (uint32_t *)
477                             OCMalloc(PresenceTimeOutSize * sizeof(uint32_t));
478                     if(!(cbNode->presence->timeOut)){
479                         OCFree(cbNode->presence);
480                         goto exit;
481                     }
482                 }
483                 if(maxAge == 0)
484                 {
485                     OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
486                     response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
487                     if(cbNode->presence)
488                     {
489                         OCFree(cbNode->presence->timeOut);
490                         OCFree(cbNode->presence);
491                         cbNode->presence = NULL;
492                     }
493                 }
494                 else
495                 {
496                     OC_LOG_V(INFO, TAG, "===============Update presence TTL, now time is %d", GetTime(0));
497                     cbNode->presence->TTL = maxAge;
498                     for(int index = 0; index < PresenceTimeOutSize; index++)
499                     {
500                         lowerBound = GetTime(((float)(PresenceTimeOut[index])
501                                 /(float)100)*(float)cbNode->presence->TTL);
502                         higherBound = GetTime(((float)(PresenceTimeOut[index + 1])
503                                 /(float)100)*(float)cbNode->presence->TTL);
504                         cbNode->presence->timeOut[index] = OCGetRandomRange(lowerBound, higherBound);
505                         OC_LOG_V(DEBUG, TAG, "----------------lowerBound timeout  %d", lowerBound);
506                         OC_LOG_V(DEBUG, TAG, "----------------higherBound timeout %d", higherBound);
507                         OC_LOG_V(DEBUG, TAG, "----------------timeOut entry  %d", cbNode->presence->timeOut[index]);
508                     }
509                     cbNode->presence->TTLlevel = 0;
510                     OC_LOG_V(DEBUG, TAG, "----------------this TTL level %d", cbNode->presence->TTLlevel);
511                     if(cbNode->sequenceNumber == clientResponse.sequenceNumber)
512                     {
513                         OC_LOG(INFO, TAG, PCF("===============No presence change"));
514                         goto exit;
515                     }
516                     OC_LOG(INFO, TAG, PCF("===============Presence changed, calling up the stack"));
517                     cbNode->sequenceNumber = clientResponse.sequenceNumber;;
518                 }
519
520                 // Ensure that a filter is actually applied.
521                 if(resourceTypeName && response->cbNode->filterResourceType)
522                 {
523                     if(!findResourceType(response->cbNode->filterResourceType, resourceTypeName))
524                     {
525                         goto exit;
526                     }
527                 }
528             }
529             else if(isMulticastPresence)
530             {
531                 // Check if the same nonce for a given host
532                 OCMulticastNode* mcNode = NULL;
533                 unsigned char senderUri[MAX_URI_LENGTH] = { 0 };
534                 snprintf((char *)senderUri, sizeof(senderUri), "%d.%d.%d.%d:%d",
535                     remoteIpAddr[0],remoteIpAddr[1],remoteIpAddr[2],remoteIpAddr[3],
536                     remotePortNu);
537                 mcNode = GetMCPresenceNode(senderUri);
538
539                 if(maxAge == 0)
540                 {
541                     OC_LOG(INFO, TAG, PCF("===============Stopping presence"));
542                     response->clientResponse->result = OC_STACK_PRESENCE_STOPPED;
543                     if(cbNode->presence)
544                     {
545                         OCFree(cbNode->presence->timeOut);
546                         OCFree(cbNode->presence);
547                         cbNode->presence = NULL;
548                     }
549                 }
550                 else if(mcNode != NULL)
551                 {
552                     if(mcNode->nonce == clientResponse.sequenceNumber)
553                     {
554                         OC_LOG(INFO, TAG, PCF("===============No presence change (Multicast)"));
555                         goto exit;
556                     }
557                     mcNode->nonce = clientResponse.sequenceNumber;
558                 }
559                 else
560                 {
561                     uint32_t uriLen = strlen((char*)senderUri);
562                     unsigned char* uri = (unsigned char *) OCMalloc(uriLen + 1);
563                     if(uri)
564                     {
565                         memcpy(uri, senderUri, (uriLen + 1));
566                     }
567                     else
568                     {
569                         OC_LOG(INFO, TAG,
570                             PCF("===============No Memory for URI to store in the presence node"));
571                         goto exit;
572                     }
573                     result = AddMCPresenceNode(&mcNode, (unsigned char*) uri,
574                                                 clientResponse.sequenceNumber);
575                     if(result == OC_STACK_NO_MEMORY)
576                     {
577                         OC_LOG(INFO, TAG,
578                             PCF("===============No Memory for Multicast Presence Node"));
579                         goto exit;
580                     }
581                 }
582
583                 // Ensure that a filter is actually applied.
584                 if(resourceTypeName && response->cbNode->filterResourceType)
585                 {
586                     if(!findResourceType(response->cbNode->filterResourceType, resourceTypeName))
587                     {
588                         goto exit;
589                     }
590                 }
591             }
592             #endif
593         }
594         HandleStackResponses(response);
595     }
596     else if(!cbNode && isObserveNotification)
597     {
598         OC_LOG(INFO, TAG, PCF("Received an observe notification, but I do not have callback \
599                  ------------ sending RESET"));
600         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
601                 recvPdu->hdr->id, NULL, NULL, NULL);
602         VERIFY_NON_NULL(sendPdu);
603         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
604                      (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
605         VERIFY_SUCCESS(result, OC_STACK_OK);
606     }
607     #ifdef WITH_PRESENCE
608     else if(!cbNode && isPresenceNotification)
609     {
610         OC_LOG(INFO, TAG, PCF("Received a presence notification, but I do not have callback \
611                      ------------ ignoring"));
612     }
613     #endif
614     else
615     {
616         OC_LOG(INFO, TAG, PCF("Received a response, but I do not have callback. \
617                  ------------ sending RESET"));
618         sendPdu = GenerateCoAPPdu(COAP_MESSAGE_RST, 0,
619                 recvPdu->hdr->id, NULL, NULL, NULL);
620         VERIFY_NON_NULL(sendPdu);
621         result = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &rcvdResponse->remote, sendPdu,
622                     (coap_send_flags_t)(rcvdResponse->secure ? SEND_SECURE_PORT : 0));
623         VERIFY_SUCCESS(result, OC_STACK_OK);
624     }
625     exit:
626         OCFree(resourceTypeName);
627         OCFree(response);
628 }
629
630 //=============================================================================
631 // Functions
632 //=============================================================================
633
634 /**
635  * Initialize the CoAP client or server with its IPv4 address and CoAP port
636  *
637  * @param ipAddr
638  *     IP Address of host device
639  * @param port
640  *     Port of host device
641  * @param mode
642  *     Host device is client, server, or client-server
643  *
644  * @return
645  *   0   - success
646  *   TBD - TBD error
647  */
648 OCStackResult OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
649
650     OCStackResult ret = OC_STACK_ERROR;
651
652     TODO ("Below should go away and be replaced by OC_LOG");
653     coap_log_t log_level = (coap_log_t)(LOG_DEBUG + 1);
654     OCDevAddr mcastAddr;
655     uint8_t ipAddr[4] = { 0 };
656     uint16_t parsedPort = 0;
657
658     OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
659
660     coap_set_log_level(log_level);
661
662     if (address)
663     {
664         if (!ParseIPv4Address((unsigned char *) address, ipAddr, &parsedPort))
665         {
666             ret = OC_STACK_ERROR;
667             goto exit;
668         }
669
670         OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",
671                                ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
672     }
673
674     gCoAPCtx = coap_new_context(ipAddr, port);
675     VERIFY_NON_NULL(gCoAPCtx);
676
677     // To allow presence notification work we need to init socket gCoAPCtx->sockfd_wellknown
678     // for servers as well as clients
679     OCBuildIPv4Address(COAP_WK_IPAddr_0, COAP_WK_IPAddr_1, COAP_WK_IPAddr_2,
680             COAP_WK_IPAddr_3, COAP_DEFAULT_PORT, &mcastAddr);
681     VERIFY_SUCCESS(
682             coap_join_wellknown_group(gCoAPCtx,
683                     (coap_address_t* )&mcastAddr), 0);
684
685     coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
686     coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
687     coap_register_ack_rst_handler(gCoAPCtx, HandleCoAPAckRst);
688
689     ret = OC_STACK_OK;
690
691 exit:
692     if (ret != OC_STACK_OK)
693     {
694         OCStopCoAP();
695     }
696     return ret;
697 }
698
699 /**
700  * Discover OC resources
701  *
702  * @param method          - method to perform on the resource
703  * @param qos             - Quality of Service the request will be sent on
704  * @param token           - token which will added to the request
705  * @param Uri             - URI of the resource to interact with
706  * @param payload         - the request payload to be added to the request before sending
707  *                          by the stack when discovery or resource interaction is complete
708  * @param options         - The address of an array containing the vendor specific
709  *                          header options to be sent with the request
710  * @return
711  *   0   - success
712  *   TBD - TBD error
713  */
714 OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token,
715                      const char *Uri, const char *payload, OCHeaderOption * options, uint8_t numOptions)
716 {
717
718     OCStackResult ret = OC_STACK_ERROR;
719     coap_pdu_t *pdu = NULL;
720     coap_uri_t uri;
721     OCDevAddr dst;
722     uint8_t ipAddr[4] = { 0 };
723     uint16_t port = 0;
724     coap_list_t *optList = NULL;
725     uint8_t coapMsgType;
726     uint8_t coapMethod;
727     uint32_t observeOption;
728     coap_send_flags_t flag = (coap_send_flags_t)0;
729
730     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
731
732     if (Uri) {
733         OC_LOG_V(INFO, TAG, "URI = %s", Uri);
734         VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), OC_STACK_OK);
735
736         // Generate the destination address
737         if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr, &port)) {
738             OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
739                     &dst);
740         } else {
741             goto exit;
742         }
743
744         VERIFY_SUCCESS(FormOptionList(&optList, NULL, NULL, NULL,
745                 (uint16_t*)&uri.port, uri.path.length, uri.path.s, uri.query.length,
746                 uri.query.s, options, numOptions), OC_STACK_OK);
747
748         //TODO : Investigate the scenario where there will be no uri for OCDoCoAPResource
749         flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
750         OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
751         OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
752         OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
753         OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
754         OC_LOG_V(DEBUG, TAG, "secure uri %d", uri.secure);
755     }
756
757     coapMsgType = OCToCoAPQoS(qos, ipAddr);
758
759     // Decide method type
760     switch (method) {
761         case OC_REST_GET:
762         #ifdef WITH_PRESENCE
763         case OC_REST_PRESENCE:
764         #endif
765             coapMethod = COAP_REQUEST_GET;
766             break;
767         case OC_REST_PUT:
768             coapMethod = COAP_REQUEST_PUT;
769             break;
770         case OC_REST_POST:
771             coapMethod = COAP_REQUEST_POST;
772             break;
773         case OC_REST_DELETE:
774             coapMethod = COAP_REQUEST_DELETE;
775             break;
776         case OC_REST_OBSERVE_ALL:
777         case OC_REST_OBSERVE:
778         case OC_REST_CANCEL_OBSERVE:
779             coapMethod = COAP_REQUEST_GET;
780             observeOption = (method == OC_REST_CANCEL_OBSERVE)?
781                     OC_OBSERVE_DEREGISTER:OC_OBSERVE_REGISTER;
782             coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
783                         sizeof(observeOption), (uint8_t *)&observeOption), OrderOptions);
784             break;
785         default:
786             coapMethod = OC_REST_NOMETHOD;
787             OC_LOG(FATAL, TAG, PCF("OCDoCoAPResource only supports GET, PUT, & OBSERVE methods"));
788             break;
789     }
790
791     VERIFY_NON_NULL(gCoAPCtx);
792     pdu = GenerateCoAPPdu(coapMsgType, coapMethod,
793             coap_new_message_id(gCoAPCtx), token,
794             (unsigned char*) payload, optList);
795     VERIFY_NON_NULL(pdu);
796
797     ret = SendCoAPPdu(gCoAPCtx, (coap_address_t*) &dst, pdu, flag);
798
799 exit:
800     if (ret!= OC_STACK_OK)
801     {
802         OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
803     }
804     return ret;
805 }
806
807 OCStackResult OCDoCoAPResponse(OCServerProtocolResponse *response)
808 {
809     OCStackResult result = OC_STACK_ERROR;
810     coap_pdu_t * sendPdu = NULL;
811     coap_list_t *optList = NULL;
812     uint8_t msgType = COAP_MESSAGE_NON;
813     uint8_t mediaType = COAP_MEDIATYPE_APPLICATION_JSON;
814     uint32_t maxAge = 0x2ffff;
815     coap_send_flags_t sendFlag = (coap_send_flags_t)0;
816
817     //uint32_t observeOption = OC_OBSERVE_NO_OPTION;
818     //OCStackResult responseResult;
819
820     OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResponse"));
821
822     if(response->notificationFlag && response->qos == OC_HIGH_QOS)
823     {
824         msgType = COAP_MESSAGE_CON;
825     }
826     else if(response->notificationFlag && response->qos != OC_HIGH_QOS)
827     {
828         msgType = COAP_MESSAGE_NON;
829     }
830     else if(!response->notificationFlag && !response->slowFlag && response->qos == OC_HIGH_QOS)
831     {
832         msgType = COAP_MESSAGE_ACK;
833     }
834     else if(!response->notificationFlag && response->slowFlag && response->qos == OC_HIGH_QOS)
835     {
836         msgType = COAP_MESSAGE_CON;
837     }
838     else if(!response->notificationFlag)
839     {
840         msgType = COAP_MESSAGE_NON;
841     }
842
843     if(response->coapID == 0)
844     {
845         response->coapID = coap_new_message_id(gCoAPCtx);
846     }
847
848     if (response->observationOption != OC_OBSERVE_NO_OPTION)
849     {
850         result = FormOptionList(&optList, &mediaType, &maxAge,
851                 &response->observationOption, NULL,
852                 strlen((char *)response->resourceUri), response->resourceUri,
853                 0, NULL,
854                 response->sendVendorSpecificHeaderOptions,
855                 response->numSendVendorSpecificHeaderOptions);
856     }
857     else
858     {
859         result = FormOptionList(&optList, &mediaType, &maxAge,
860                 NULL, NULL,
861                 strlen((char *)response->resourceUri), response->resourceUri,
862                 0, NULL,
863                 response->sendVendorSpecificHeaderOptions,
864                 response->numSendVendorSpecificHeaderOptions);
865     }
866     VERIFY_SUCCESS(result, OC_STACK_OK);
867
868     sendPdu = GenerateCoAPPdu(msgType, OCToCoAPResponseCode(response->result),
869             response->coapID, response->requestToken, (unsigned char *)response->payload,
870             optList);
871
872     VERIFY_NON_NULL(sendPdu);
873     coap_show_pdu(sendPdu);
874
875     sendFlag = (coap_send_flags_t)(response->delayedResNeeded ? SEND_DELAYED : 0);
876     sendFlag = (coap_send_flags_t)( sendFlag | (response->secured ? SEND_SECURE_PORT : 0));
877
878     if (SendCoAPPdu(gCoAPCtx, (coap_address_t *) (response->requesterAddr), sendPdu, sendFlag)
879             != OC_STACK_OK)
880     {
881         OC_LOG(ERROR, TAG, PCF("A problem occurred in sending a pdu"));
882         return OC_STACK_ERROR;
883     }
884
885     return OC_STACK_OK;
886
887 exit:
888     OC_LOG(ERROR, TAG, PCF("Error formatting server response"));
889     return OC_STACK_ERROR;
890 }
891
892
893 /**
894  * Stop the CoAP client or server processing
895  *
896  * @return 0 - success, else - TBD error
897  */
898 OCStackResult OCStopCoAP() {
899     OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP"));
900     coap_free_context(gCoAPCtx);
901     gCoAPCtx = NULL;
902     return OC_STACK_OK;
903 }
904
905 /**
906  * Called in main loop of CoAP client or server.  Allows low-level CoAP processing of
907  * send, receive, timeout, discovery, callbacks, etc.
908  *
909  * @return 0 - success, else - TBD error
910  */
911 OCStackResult OCProcessCoAP() {
912     int read = 0;
913     read = coap_read(gCoAPCtx, gCoAPCtx->sockfd);
914     if(read > 0) {
915         OC_LOG(INFO, TAG, PCF("This is a Unicast<============"));
916     }
917     if (-1 != gCoAPCtx->sockfd_wellknown) {
918         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_wellknown);
919         if(read > 0)
920         {
921             OC_LOG(INFO, TAG, PCF("This is a Multicast<==========="));
922         }
923     }
924     if (-1 != gCoAPCtx->sockfd_dtls) {
925         read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_dtls);
926         if(read > 0)
927         {
928             OC_LOG(INFO, TAG, PCF("This is a Secure packet<==========="));
929         }
930     }
931     coap_dispatch(gCoAPCtx);
932
933     HandleSendQueue(gCoAPCtx);
934
935     return OC_STACK_OK;
936 }
937
938
939 /**
940  * Retrieve the info about the end-point where resource is being hosted.
941  * Currently, this method only provides the IP port with which the socket
942  * is bound.
943  *
944  * @return 0 - success, else - TBD error
945  */
946 OCStackResult OCGetResourceEndPointInfo (OCResource *resPtr, void *info) {
947
948     OCStackResult result = OC_STACK_ERROR;
949     int sfd;
950     OC_LOG(INFO, TAG, PCF("Entering OCGetResourceEndPointInfo"));
951     VERIFY_NON_NULL(resPtr);
952     VERIFY_NON_NULL(info);
953
954     sfd = (resPtr->resourceProperties & OC_SECURE) ? gCoAPCtx->sockfd_dtls :
955             gCoAPCtx->sockfd;
956
957     if (OCGetSocketInfo(sfd, (uint16_t*)info) == ERR_SUCCESS)
958         result = OC_STACK_OK;
959 exit:
960     return result;
961 }
962
963