1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH 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
10 // http://www.apache.org/licenses/LICENSE-2.0
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
18 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
30 #include "occlientbasicops.h"
34 #define MAX_IP_ADDR_ST_SZ 16 //string size of "155.255.255.255" (15 + 1)
35 #define MAX_PORT_ST_SZ 6 //string size of "65535" (5 + 1)
37 static int IPV4_ADDR_SIZE = 16;
38 static int UNICAST_DISCOVERY = 0;
39 static int TEST_CASE = 0;
41 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s:5298/oc/core";
42 static std::string putPayload = "{\"state\":\"off\",\"power\":10}";
44 //The following variable determines the interface (wifi, ethernet etc.)
45 //to be used for sending unicast messages. Default set to WIFI.
46 static OCConnectivityType OC_CONNTYPE = OC_WIFI;
47 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oc/core";
51 struct ResourceNode *resourceList;
53 * SIGINT handler: set gQuitFlag to 1 for graceful termination
55 void handleSigInt(int signum)
63 static void PrintUsage()
65 OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
66 OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
67 OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
68 OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
69 " Initiate Nonconfirmable Get/Put/Post Requests");
70 OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
71 "Confirmable Get/Put/Post Requests");
72 OC_LOG(INFO, TAG, "-c <0|1> : Send unicast messages over Ethernet or WIFI.");
73 OC_LOG(INFO, TAG, "Default connectivityType WIFI");
77 * Returns the first resource in the list
79 const ResourceNode * getResource()
84 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
85 OCConnectivityType connType, OCQualityOfService qos,
86 OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
89 OCCallbackData cbData;
92 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
95 ret = OCDoResource(NULL, method, query.str().c_str(), 0,
96 (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload.c_str() : NULL,
97 connType, qos, &cbData, options, numOptions);
99 if (ret != OC_STACK_OK)
101 OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
108 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle,
109 OCClientResponse * clientResponse)
111 uint8_t remoteIpAddr[4];
112 uint16_t remotePortNu;
114 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
116 OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
120 OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
125 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
126 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
127 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
129 OC_LOG_V(INFO, TAG,"PUT Response: %s \nFrom %d.%d.%d.%d:%d\n",
130 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
131 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
135 OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
137 return OC_STACK_DELETE_TRANSACTION;
140 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle,
141 OCClientResponse *clientResponse)
143 uint8_t remoteIpAddr[4];
144 uint16_t remotePortNu;
146 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
148 OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
152 OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
157 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
158 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
159 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
161 OC_LOG_V(INFO, TAG,"POST Response: %s \nFrom %d.%d.%d.%d:%d\n",
162 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
163 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
167 OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
170 return OC_STACK_DELETE_TRANSACTION;
173 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
174 OCClientResponse * clientResponse)
176 uint8_t remoteIpAddr[4];
177 uint16_t remotePortNu;
179 if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
181 OC_LOG(INFO, TAG, "<====Callback Context for GET received successfully====>");
185 OC_LOG(ERROR, TAG, "<====Callback Context for GET fail====>");
190 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr, remoteIpAddr + 1,
191 remoteIpAddr + 2, remoteIpAddr + 3);
192 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
194 OC_LOG_V(INFO, TAG,"Get Response: %s \nFrom %d.%d.%d.%d:%d\n",
195 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
196 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
198 if (clientResponse->rcvdVendorSpecificHeaderOptions
199 && clientResponse->numRcvdVendorSpecificHeaderOptions)
201 OC_LOG (INFO, TAG, "Received vendor specific options");
203 OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
204 for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
206 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
208 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
209 ((OCHeaderOption)rcvdOptions[i]).optionID );
210 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
211 ((OCHeaderOption)rcvdOptions[i]).optionLength);
218 OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
220 return OC_STACK_DELETE_TRANSACTION;
224 * This is a function called back when a device is discovered
226 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
227 OCClientResponse * clientResponse)
229 uint8_t remoteIpAddr[4];
230 uint16_t remotePortNu;
231 if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
233 OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
234 "received successfully====>");
238 OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
243 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
244 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
245 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
248 "Device Discovered %s \n @ %d.%d.%d.%d:%d\n",
249 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
250 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
252 collectUniqueResource(clientResponse);
256 OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
258 return (UNICAST_DISCOVERY) ?
259 OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
262 int InitPutRequest(OCQualityOfService qos)
264 std::ostringstream query;
265 //Get most recently inserted resource
266 const ResourceNode * resource = getResource();
270 OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
273 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
274 OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
276 return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
277 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
281 int InitPostRequest(OCQualityOfService qos)
283 OCStackResult result;
284 std::ostringstream query;
285 //Get most recently inserted resource
286 const ResourceNode * resource = getResource();
290 OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
294 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
295 OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
297 // First POST operation (to create an LED instance)
298 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
299 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
301 if (OC_STACK_OK != result)
303 // Error can happen if for example, network connectivity is down
304 OC_LOG(ERROR, TAG, "First POST call did not succeed");
307 // Second POST operation (to create an LED instance)
308 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
309 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
311 if (OC_STACK_OK != result)
313 OC_LOG(ERROR, TAG, "Second POST call did not succeed");
316 // This POST operation will update the original resourced /a/led
317 return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
318 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
319 postReqCB, NULL, 0));
322 int InitGetRequest(OCQualityOfService qos)
324 std::ostringstream query;
325 //Get most recently inserted resource
326 const ResourceNode * resource = getResource();
330 OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
333 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
334 OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
336 return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
337 (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
343 OCCallbackData cbData;
344 /* Start a discovery query*/
345 char szQueryUri[64] = { 0 };
346 if (UNICAST_DISCOVERY)
348 char ipv4addr[IPV4_ADDR_SIZE];
349 printf("Enter IPv4 address of the Server hosting "
350 "resource (Ex: 192.168.0.15)\n");
351 if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
353 //Strip newline char from ipv4addr
354 StripNewLineChar(ipv4addr);
355 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
359 OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
360 return OC_STACK_INVALID_PARAM;
365 strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
367 cbData.cb = discoveryReqCB;
368 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
370 if (UNICAST_DISCOVERY)
372 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
373 OC_LOW_QOS, &cbData, NULL, 0);
377 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, (OC_ALL),
378 OC_LOW_QOS, &cbData, NULL, 0);
381 if (ret != OC_STACK_OK)
383 OC_LOG(ERROR, TAG, "OCStack resource error");
390 const char * getIPAddr(const OCClientResponse * clientResponse)
393 if(!clientResponse || 0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d))
398 char * ipaddr = NULL;
399 if((ipaddr = (char *) OCCalloc(1, MAX_IP_ADDR_ST_SZ)))
401 snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%d.%d.%d.%d", a,b,c,d);
405 OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
410 const char * getPort(const OCClientResponse * clientResponse)
413 if(!clientResponse || 0 != OCDevAddrToPort(clientResponse->addr, &p) )
419 if((port = (char *) OCCalloc(1, MAX_PORT_ST_SZ)))
421 snprintf(port, MAX_PORT_ST_SZ, "%d", p);
425 OC_LOG(ERROR, TAG, "Memory not allocated to port");
430 int parseJSON(unsigned const char * resJSONPayload, char ** sid_c,
431 char *** uri_c, int * totalRes)
436 root = cJSON_Parse((char *)(resJSONPayload));
440 OC_LOG(ERROR, TAG, "JSON Parsing Error");
441 return OC_STACK_INVALID_JSON;
444 oc = cJSON_GetObjectItem(root,"oc");
447 OC_LOG(ERROR, TAG, "Invalid JSON : Missing oc object");
448 return OC_STACK_INVALID_JSON;
451 * totalRes = cJSON_GetArraySize(oc);
453 if(oc->type == cJSON_Array)
455 cJSON * resource = cJSON_GetArrayItem(oc, 0);
459 return OC_STACK_INVALID_JSON;
462 if (cJSON_GetObjectItem(resource, "sid"))
464 char * sid = cJSON_GetObjectItem(resource, "sid")->valuestring;
465 if((* sid_c = (char *)OCCalloc(1, strlen (sid) + 1)))
467 memcpy(* sid_c, sid, strlen(sid) + 1);
471 OC_LOG(ERROR, TAG, "Memory not allocated to sid");
472 return OC_STACK_NO_MEMORY;
477 OC_LOG(ERROR, TAG, "Invalid JSON : Missing sid object");
478 return OC_STACK_INVALID_JSON;
481 if(!(* uri_c = (char ** )OCMalloc ((* totalRes) * sizeof(char **))))
483 OC_LOG(ERROR, TAG, "Memory not allocated to sid_c array");
484 return OC_STACK_NO_MEMORY;
491 if (cJSON_GetObjectItem(resource, "href"))
493 char *uri= cJSON_GetObjectItem(resource, "href")->valuestring;
494 if(((*uri_c)[i] = (char *)OCCalloc(1, strlen (uri) + 1)))
496 memcpy((*uri_c)[i], uri, strlen(uri) + 1);
500 OC_LOG(ERROR, TAG, "Memory not allocated to uri");
501 return OC_STACK_NO_MEMORY;
504 if(i >= (* totalRes))
506 resource = cJSON_GetArrayItem(oc, i);
510 OC_LOG(ERROR, TAG, "Invalid JSON : Missing uri object");
511 return OC_STACK_INVALID_JSON;
517 return OC_STACK_INVALID_JSON;
518 OC_LOG(ERROR, TAG, "Invalid JSON : oc object type is not an array");
528 case TEST_DISCOVER_REQ:
530 case TEST_NON_CON_OP:
531 InitGetRequest(OC_LOW_QOS);
532 InitPutRequest(OC_LOW_QOS);
533 InitPostRequest(OC_LOW_QOS);
536 InitGetRequest(OC_HIGH_QOS);
537 InitPutRequest(OC_HIGH_QOS);
538 InitPostRequest(OC_HIGH_QOS);
548 void collectUniqueResource(const OCClientResponse * clientResponse)
554 if(parseJSON(clientResponse->resJSONPayload, & sid, & uri, &totalRes)
557 OC_LOG(ERROR, TAG, "Error while parsing JSON payload in OCClientResponse");
561 for(i = 0; i < totalRes; i++)
563 if(insertResource(sid, uri[i], clientResponse) == 1)
565 printf("%s%s%s%s\n",sid, ":", uri[i], " is new");
571 printf("%s%s%s%s\n\n",sid, ":", uri[i], " has been seen before");
578 /* This function searches for the resource(sid:uri) in the ResourceList.
579 * If the Resource is found in the list then it returns 0 else insert
580 * the resource to front of the list and returns 1.
582 int insertResource(const char * sid, char const * uri,
583 const OCClientResponse * clientResponse)
585 ResourceNode * iter = resourceList;
587 //Checking if the resource(sid:uri) is new
590 if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
600 //Creating new ResourceNode
601 if((iter = (ResourceNode *) OCMalloc(sizeof(ResourceNode))))
605 iter->ip = getIPAddr(clientResponse);
606 iter->port = getPort(clientResponse);
607 iter->connType = clientResponse->connType;
612 OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
616 //Adding new ResourceNode to front of the ResourceList
623 iter->next = resourceList;
629 void printResourceList()
633 printf("\nResource List\n");
636 printf("*****************************************************\n");
637 printf("sid = %s \n",iter->sid);
638 printf("uri = %s\n", iter->uri);
639 printf("ip = %s\n", iter->ip);
640 printf("port = %s\n", iter->port);
641 switch (iter->connType)
644 printf("connType = %s\n","Ethernet");
647 printf("connType = %s\n","WiFi");
650 printf("connType = %s\n","BLE");
653 printf("connType = %s\n","BT");
657 printf("connType = %s\n","Invalid connType");
660 printf("*****************************************************\n");
665 void freeResourceList()
667 OC_LOG(INFO, TAG, "Freeing ResourceNode List");
672 resourceList = resourceList->next;
673 OCFree((void *)temp->sid);
674 OCFree((void *)temp->uri);
675 OCFree((void *)temp->ip);
676 OCFree((void *)temp->port);
681 int main(int argc, char* argv[])
685 while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
690 UNICAST_DISCOVERY = atoi(optarg);
693 TEST_CASE = atoi(optarg);
696 OC_CONNTYPE = OCConnectivityType(atoi(optarg));
704 if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
705 (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
711 /* Initialize OCStack*/
712 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
714 OC_LOG(ERROR, TAG, "OCStack init error");
720 // Break from loop with Ctrl+C
721 signal(SIGINT, handleSigInt);
725 if (OCProcess() != OC_STACK_OK)
727 OC_LOG(ERROR, TAG, "OCStack process error");
734 OC_LOG(INFO, TAG, "Exiting occlient main loop...");
735 if (OCStop() != OC_STACK_OK)
737 OC_LOG(ERROR, TAG, "OCStack stop error");