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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 //=============================================================================
24 //=============================================================================
26 #include "occlientcb.h"
35 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
38 #define TAG PCF("OCCoAP")
39 #define VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
40 {OC_LOG(FATAL, TAG, #op " failed !!"); goto exit;} }
41 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, TAG, #arg " is NULL"); goto exit;} }
44 #define BUF_SIZE_ENCODE_OPTION (3)
45 #define BUF_SIZE_PORT (2)
47 //=============================================================================
49 //=============================================================================
51 static uint8_t coapWKIpAddr[] = { 224, 0, 1, 187 };
52 static coap_context_t *gCoAPCtx = NULL;
54 //=============================================================================
56 //=============================================================================
58 //generate a coap token
59 OCCoAPToken * OCGenerateCoAPToken() {
61 // Generate token here, it will be deleted when the transaction is deleted
62 token = (OCCoAPToken *) malloc(sizeof(OCCoAPToken));
63 token->tokenLength = MAX_TOKEN_LENGTH;
64 OCFillRandomMem((uint8_t*)token->token, token->tokenLength);
66 //OC_LOG_V(INFO,TAG,"Toke n generated %d bytes..........%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
67 // token->tokenLength,token->token[0],token->token[1],token->token[2],token->token[3],
68 // token->token[4],token->token[5],token->token[6],token->token[7]);
71 //This function is called back by libcoap when a request is received
72 static void HandleCoAPRequests(struct coap_context_t *ctx,
73 const coap_queue_t * rcvdRequest)
79 OCRequest * request = NULL;
80 OCEntityHandlerRequest * entityHandlerRequest = NULL;
81 OCCoAPToken * rcvdToken = NULL;
83 unsigned char rcvdUri[MAX_URI_LENGTH] = { 0 };
84 unsigned char rcvdQuery[MAX_QUERY_LENGTH] = { 0 };
86 unsigned char bufRes[MAX_RESPONSE_LENGTH] = { 0 };
88 coap_list_t *optList = NULL;
89 unsigned char tempBuf[BUF_SIZE_ENCODE_OPTION];
91 coap_tid_t tid = COAP_INVALID_TID;
93 // fill OCRequest structure
94 result = FormOCRequest(rcvdRequest, &request, rcvdUri, rcvdQuery);
95 VERIFY_SUCCESS(result, OC_STACK_OK);
97 // fill OCEntityHandlerRequest structure
98 result = FormOCEntityHandlerRequest(rcvdRequest, &entityHandlerRequest,
100 VERIFY_SUCCESS(result, OC_STACK_OK);
102 // fill OCCoAPToken structure
103 result = RetrieveOCCoAPToken(rcvdRequest, &rcvdToken);
104 VERIFY_SUCCESS(result, OC_STACK_OK);
106 request->entityHandlerRequest = entityHandlerRequest;
108 OC_LOG_V(INFO, TAG, " Receveid uri: %s", request->resourceUrl);
109 OC_LOG_V(INFO, TAG, " Receveid query: %s", entityHandlerRequest->query);
110 OC_LOG_V(INFO, TAG, " Receveid payload: %s",
111 request->entityHandlerRequest->reqJSONPayload);
113 if(GetClientCB(rcvdToken, 0)) { //True if the token was found in the list of clientCBs
114 OC_LOG_V(INFO, TAG, " Token received %d bytes",
115 rcvdToken->tokenLength);
116 OC_LOG_BUFFER(INFO, TAG, rcvdToken->token, rcvdToken->tokenLength);
119 // process the request
120 result = HandleStackRequests(request);
122 if (result == OC_STACK_OK)
124 OC_LOG_V(INFO, TAG, "Response from ocstack: %s", request->entityHandlerRequest->resJSONPayload);
125 // need to build the response PDU
126 coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE,
127 coap_encode_var_bytes(tempBuf, COAP_MEDIATYPE_APPLICATION_JSON),
128 tempBuf), OrderOptions);
129 coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_MAXAGE,
130 coap_encode_var_bytes(tempBuf, 0x2ffff), tempBuf),
134 // generate the pdu, if the request was CON, then the response is ACK, otherwire NON
135 pdu = GenerateCoAPPdu(
136 rcvdRequest->pdu->hdr->type == COAP_MESSAGE_CON ?
137 COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
138 OCToCoAPResponseCode(result), rcvdRequest->pdu->hdr->id,
139 rcvdToken->tokenLength, rcvdToken->token,
140 request->entityHandlerRequest->resJSONPayload, optList);
141 VERIFY_NON_NULL(pdu);
144 if (pdu->hdr->type != COAP_MESSAGE_NON
145 || (pdu->hdr->code >= 64 && !coap_is_mcast(&rcvdRequest->local)))
147 tid = coap_send(gCoAPCtx, &rcvdRequest->remote, pdu);
150 OC_LOG_V(INFO, TAG, "TID %d", tid);
151 // unlike stock libcoap (deletion in handle_request in net.c), we are deleting the response here
152 // in the future, the response might be queued for SLOW resources
153 if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
155 OC_LOG(INFO, TAG, "Deleting PDU");
156 coap_delete_pdu(pdu);
160 coap_delete_list(optList);
165 OCFree(entityHandlerRequest);
169 //This function is called back by libcoap when a response is received
170 static void HandleCoAPResponses(struct coap_context_t *ctx,
171 const coap_queue_t * rcvdResponse) {
172 OCResponse * response = NULL;
173 OCCoAPToken * _token = NULL;
174 OCClientResponse * clientResponse = NULL;
175 OCStackResult result;
177 VERIFY_NON_NULL(ctx);
178 VERIFY_NON_NULL(rcvdResponse);
180 // TODO: we should check if we are interested in the token
181 // Now, just accept NON packets
183 if (rcvdResponse->pdu->hdr->type == COAP_MESSAGE_NON) {
184 // fill OCResponse structure
185 result = FormOCResponse(rcvdResponse, &response);
186 VERIFY_SUCCESS(result, OC_STACK_OK);
188 // fill OCCoAPToken structure
189 result = RetrieveOCCoAPToken(rcvdResponse, &_token);
190 VERIFY_SUCCESS(result, OC_STACK_OK);
192 // fill OCClientResponse structure
193 result = FormOCClientResponse(rcvdResponse, &clientResponse);
194 VERIFY_SUCCESS(result, OC_STACK_OK);
196 // put everything together
197 ClientCB * clientCB = GetClientCB(_token, NULL);
198 OCDoHandle *handle = NULL;
200 handle = clientCB->handle;
201 response->handle = handle;
203 response->clientResponse = clientResponse;
205 OC_LOG_V(INFO, TAG, " Received a response HandleCoAPResponses in occoap: %s",
206 response->clientResponse->resJSONPayload);
207 OC_LOG_V(INFO, TAG,"Token received %d bytes", _token->tokenLength);
208 OC_LOG_BUFFER(INFO, TAG, _token->token,
209 _token->tokenLength);
211 response->clientResponse->result = OC_STACK_OK;
212 HandleStackResponses(response);
213 /*if (rcvdResponse->pdu->hdr->code == COAP_RESPONSE_CODE(205))
215 response->clientResponse->result = OC_STACK_OK;
216 HandleStackResponses(response);
221 "No other response codes are supported in HandleCoAPResponses");
226 OC_LOG(DEBUG, TAG, "Do not accept other than NON in HandleCoAPResponses");
235 OCFree(clientResponse);
238 //=============================================================================
240 //=============================================================================
243 * Initialize the CoAP client or server with its IPv4 address and CoAP port
246 * IP Address of host device
248 * Port of host device
250 * Host device is client, server, or client-server
256 int OCInitCoAP(const char *address, uint16_t port, OCMode mode) {
258 int ret = OC_COAP_ERR;
260 TODO ("Below should go away and be replaced by OC_LOG");
261 coap_log_t log_level = LOG_DEBUG + 1;
264 uint8_t ipAddr[4] = { 0 };
266 OC_LOG(INFO, TAG, PCF("Entering OCInitCoAP"));
268 coap_set_log_level(log_level);
272 if (!ParseIPv4Address((unsigned char *) address, ipAddr))
276 OC_LOG_V(INFO, TAG, "Parsed IP Address %d.%d.%d.%d",ipAddr[0],ipAddr[1],ipAddr[2],ipAddr[3]);
279 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], port,
282 gCoAPCtx = coap_new_context((coap_address_t*) &devAddr);
283 VERIFY_NON_NULL(gCoAPCtx);
284 if (mode != OC_CLIENT) {
285 OCBuildIPv4Address(coapWKIpAddr[0], coapWKIpAddr[1], coapWKIpAddr[2],
286 coapWKIpAddr[3], COAP_DEFAULT_PORT, &mcastAddr);
288 coap_join_wellknown_group(gCoAPCtx,
289 (coap_address_t* )&mcastAddr), 0);
292 coap_register_request_handler(gCoAPCtx, HandleCoAPRequests);
293 coap_register_response_handler(gCoAPCtx, HandleCoAPResponses);
302 * Discover OC resources
304 * @param method - method to perform on the resource
305 * @param qos - Quality of Service the request will be sent on
306 * @param token - token which will added to the request
307 * @param Uri - URI of the resource to interact with
308 * @param payload - the request payload to be added to the request before sending
309 * by the stack when discovery or resource interaction is complete
314 int OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPToken * token,
315 const char *Uri, const char *payload)
318 int ret = OC_COAP_ERR;
319 coap_pdu_t *pdu = NULL;
321 coap_tid_t tid = COAP_INVALID_TID;
323 uint8_t ipAddr[4] = { 0 };
324 coap_list_t *optList = NULL;
325 unsigned char portBuf[BUF_SIZE_PORT];
327 unsigned char _buf[BUF_SIZE];
328 unsigned char *buf = _buf;
332 // Vijay: TODO Observation registration is hardcoded here - change
333 unsigned char obs[] = "0";
335 OC_LOG(INFO, TAG, PCF("Entering OCDoCoAPResource"));
338 OC_LOG_V(INFO, TAG, "URI = %s", Uri);
341 VERIFY_SUCCESS(coap_split_uri((unsigned char * )Uri, strlen(Uri), &uri), 0);
343 // Generate the destination address
344 if (uri.host.length && ParseIPv4Address(uri.host.s, ipAddr)) {
345 OCBuildIPv4Address(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3], uri.port,
351 //create appropriate coap options
352 if (uri.port != COAP_DEFAULT_PORT) {
353 coap_insert(&optList,
354 CreateNewOptionNode(COAP_OPTION_URI_PORT,
355 coap_encode_var_bytes(portBuf, uri.port), portBuf),
359 if (uri.path.length) {
361 res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
364 coap_insert(&optList,
365 CreateNewOptionNode(COAP_OPTION_URI_PATH,
366 COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
369 buf += COAP_OPT_SIZE(buf);
373 if (uri.query.length) {
376 res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
379 coap_insert(&optList,
380 CreateNewOptionNode(COAP_OPTION_URI_QUERY,
381 COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
384 buf += COAP_OPT_SIZE(buf);
388 OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
389 OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
390 OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
391 OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
393 coapMsgType = COAP_MESSAGE_NON;
395 // Decide message type
396 if (qos == OC_CONFIRMABLE) {
397 coapMsgType = COAP_MESSAGE_CON;
398 OC_LOG(FATAL, TAG, "qos == OC_CONFIRMABLE is not supported in OCDoCoAPResource");
401 // Decide method type
404 coapMethod = COAP_REQUEST_GET;
407 coapMethod = COAP_REQUEST_PUT;
409 case OC_REST_OBSERVE_ALL:
410 case OC_REST_OBSERVE:
411 coapMethod = COAP_REQUEST_GET;
413 // Joey's add for observation registration: not working.
414 // Vijay's change below
417 res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
418 //Set observe option flag.
420 coap_insert(&optList,
421 CreateNewOptionNode(COAP_OPTION_SUBSCRIPTION,
422 COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)),
425 buf += COAP_OPT_SIZE(buf);
428 coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
429 strlen((const char *)obs), (obs)), OrderOptions);
434 OC_LOG(FATAL, TAG, "OCDoCoAPResource only supports GET, PUT, & OBSERVE methods");
438 VERIFY_NON_NULL(gCoAPCtx);
439 pdu = GenerateCoAPPdu(coapMsgType, coapMethod,
440 coap_new_message_id(gCoAPCtx), token->tokenLength, token->token,
441 (unsigned char*) payload, optList);
442 VERIFY_NON_NULL(pdu);
444 TODO ("Post Sprint 1 -- Send Confirmed requests for non-discovery requests");
445 tid = coap_send(gCoAPCtx, (coap_address_t*) &dst, pdu);
447 OC_LOG_V(INFO, TAG, "TID %d", tid);
448 if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
450 OC_LOG(INFO, TAG, "Deleting PDU");
451 coap_delete_pdu(pdu);
456 OC_LOG(INFO, TAG, "Keeping PDU, we should handle the retry of this pdu");
462 coap_delete_list(optList);
463 if (ret != OC_COAP_OK)
465 coap_delete_pdu(pdu);
470 int OCCoAPSendMessage (OCDevAddr *dstAddr, OCStackResult msgCode,
471 OCQualityOfService qos, OCCoAPToken * token,
472 const char *payload, uint32_t seqNum)
474 coap_list_t *optList = NULL;
476 unsigned char tempBuf[BUF_SIZE_ENCODE_OPTION];
477 uint8_t coapMsgType = COAP_MESSAGE_NON;
478 coap_tid_t tid = COAP_INVALID_TID;
480 OC_LOG(INFO, TAG, PCF("Entering OCCoAPSendMessage"));
482 printf ("Payload: %s\n", payload);
483 OC_LOG_V(INFO, TAG, "OCStack payload: %s", payload);
484 coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_CONTENT_TYPE,
485 coap_encode_var_bytes(tempBuf, COAP_MEDIATYPE_APPLICATION_JSON),
486 tempBuf), OrderOptions);
487 coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_MAXAGE,
488 coap_encode_var_bytes(tempBuf, 0x2ffff), tempBuf), OrderOptions);
489 coap_insert(&optList, CreateNewOptionNode(COAP_OPTION_OBSERVE,
490 coap_encode_var_bytes(tempBuf, seqNum), tempBuf), OrderOptions);
492 pdu = GenerateCoAPPdu (coapMsgType, OCToCoAPResponseCode(msgCode),
493 coap_new_message_id(gCoAPCtx), token->tokenLength, token->token,
494 (unsigned char*) payload, optList);
495 VERIFY_NON_NULL(pdu);
498 tid = coap_send(gCoAPCtx, (coap_address_t*)dstAddr, pdu);
499 OC_LOG_V(INFO, TAG, "TID %d", tid);
500 if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
502 OC_LOG(INFO, TAG, "Deleting PDU");
503 coap_delete_pdu(pdu);
509 coap_delete_list(optList);
514 * Stop the CoAP client or server processing
516 * @return 0 - success, else - TBD error
519 OC_LOG(INFO, TAG, PCF("Entering OCStopCoAP"));
520 coap_free_context(gCoAPCtx);
526 * Called in main loop of CoAP client or server. Allows low-level CoAP processing of
527 * send, receive, timeout, discovery, callbacks, etc.
529 * @return 0 - success, else - TBD error
531 int OCProcessCoAP() {
532 OC_LOG(INFO, TAG, PCF("Entering OCProcessCoAP"));
534 coap_read(gCoAPCtx, gCoAPCtx->sockfd);
535 if (-1 != gCoAPCtx->sockfd_wellknown) {
536 coap_read(gCoAPCtx, gCoAPCtx->sockfd_wellknown);
538 coap_dispatch(gCoAPCtx);