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"
32 #include "oic_malloc.h"
33 #include "oic_string.h"
35 #define MAX_IP_ADDR_ST_SZ 16 //string size of "155.255.255.255" (15 + 1)
36 #define MAX_PORT_ST_SZ 6 //string size of "65535" (5 + 1)
38 static int IPV4_ADDR_SIZE = 24;
39 static int UNICAST_DISCOVERY = 0;
40 static int TEST_CASE = 0;
41 static int CONNECTIVITY = 0;
43 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s/oic/res";
44 static std::string putPayload = "{\"oic\":[{\"rep\":{\"power\":15,\"state\":true}}]}";
46 //The following variable determines the interface protocol (IP, etc)
47 //to be used for sending unicast messages. Default set to IP.
48 static OCConnectivityType OC_CONNTYPE = CT_ADAPTER_IP;
49 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
53 struct ResourceNode *resourceList;
55 * SIGINT handler: set gQuitFlag to 1 for graceful termination
57 void handleSigInt(int signum)
65 static void PrintUsage()
67 OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
68 OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
69 OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
70 OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
71 " Initiate Nonconfirmable Get/Put/Post Requests");
72 OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
73 "Confirmable Get/Put/Post Requests");
74 OC_LOG(INFO, TAG, "-c 0 : Default auto-selection");
75 OC_LOG(INFO, TAG, "-c 1 : IP Connectivity Type");
79 * Returns the first resource in the list
81 const ResourceNode * getResource()
86 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
87 OCConnectivityType connType, OCQualityOfService qos,
88 OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
91 OCCallbackData cbData;
94 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
97 ret = OCDoResource(NULL, method, query.str().c_str(), 0,
98 (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload.c_str() : NULL,
99 connType, qos, &cbData, options, numOptions);
101 if (ret != OC_STACK_OK)
103 OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
110 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle,
111 OCClientResponse * clientResponse)
113 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
115 OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
119 OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
124 OC_LOG_V(INFO, TAG,"PUT Response: %s \nFrom %s:%d\n",
125 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
129 OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
131 return OC_STACK_DELETE_TRANSACTION;
134 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle,
135 OCClientResponse *clientResponse)
137 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
139 OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
143 OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
148 OC_LOG_V(INFO, TAG,"POST Response: %s \nFrom %s:%d\n",
149 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
153 OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
156 return OC_STACK_DELETE_TRANSACTION;
159 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
160 OCClientResponse * clientResponse)
162 if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
164 OC_LOG(INFO, TAG, "<====Callback Context for GET received successfully====>");
168 OC_LOG(ERROR, TAG, "<====Callback Context for GET fail====>");
173 OC_LOG_V(INFO, TAG,"Get Response: %s \nFrom %s:%d\n",
174 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
176 if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0 )
178 OC_LOG (INFO, TAG, "Received vendor specific options");
180 OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
181 for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
183 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
185 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
186 ((OCHeaderOption)rcvdOptions[i]).optionID );
188 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
189 MAX_HEADER_OPTION_DATA_LENGTH);
196 OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
198 return OC_STACK_DELETE_TRANSACTION;
202 * This is a function called back when a device is discovered
204 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
205 OCClientResponse * clientResponse)
207 if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
209 OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
210 "received successfully====>");
214 OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
220 "Device Discovered %s \n @ %s:%d\n",
221 clientResponse->resJSONPayload, clientResponse->devAddr.addr, clientResponse->devAddr.port);
223 collectUniqueResource(clientResponse);
227 OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
229 return (UNICAST_DISCOVERY) ?
230 OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
233 int InitPutRequest(OCQualityOfService qos)
235 std::ostringstream query;
236 //Get most recently inserted resource
237 const ResourceNode * resource = getResource();
241 OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
244 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
245 OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
247 return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
248 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
252 int InitPostRequest(OCQualityOfService qos)
254 OCStackResult result;
255 std::ostringstream query;
256 //Get most recently inserted resource
257 const ResourceNode * resource = getResource();
261 OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
265 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
266 OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
268 // First POST operation (to create an LED instance)
269 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
270 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
272 if (OC_STACK_OK != result)
274 // Error can happen if for example, network connectivity is down
275 OC_LOG(ERROR, TAG, "First POST call did not succeed");
278 // Second POST operation (to create an LED instance)
279 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
280 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
282 if (OC_STACK_OK != result)
284 OC_LOG(ERROR, TAG, "Second POST call did not succeed");
287 // This POST operation will update the original resourced /a/led
288 return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
289 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
290 postReqCB, NULL, 0));
293 int InitGetRequest(OCQualityOfService qos)
295 std::ostringstream query;
296 //Get most recently inserted resource
297 const ResourceNode * resource = getResource();
301 OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
304 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
305 OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
307 return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
308 (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
314 OCCallbackData cbData;
315 /* Start a discovery query*/
316 char szQueryUri[64] = {};
317 if (UNICAST_DISCOVERY)
319 char ipv4addr[IPV4_ADDR_SIZE];
320 OC_LOG(INFO, TAG, "Enter IP address with port of the Server hosting resource"\
321 "(Ex: 192.168.0.15:1234) ");
323 if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
325 //Strip newline char from ipv4addr
326 StripNewLineChar(ipv4addr);
327 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
331 OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
332 return OC_STACK_INVALID_PARAM;
337 strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
339 cbData.cb = discoveryReqCB;
340 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
342 if (UNICAST_DISCOVERY)
344 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
345 OC_LOW_QOS, &cbData, NULL, 0);
349 ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT,
350 OC_LOW_QOS, &cbData, NULL, 0);
353 if (ret != OC_STACK_OK)
355 OC_LOG(ERROR, TAG, "OCStack resource error");
360 const char *getIPAddr(const OCClientResponse *clientResponse)
367 const OCDevAddr *devAddr = &clientResponse->devAddr;
368 char *ipaddr = (char *) OICCalloc(1, strlen(devAddr->addr) +1);
371 snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%s", devAddr->addr);
375 OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
380 const char *getPort(const OCClientResponse *clientResponse)
388 if((port = (char *)OICCalloc(1, MAX_PORT_ST_SZ)))
390 snprintf(port, MAX_PORT_ST_SZ, "%d", clientResponse->devAddr.port);
394 OC_LOG(ERROR, TAG, "Memory not allocated to port");
399 int parseJSON(const char * resJSONPayload, char ** sid_c,
400 char *** uri_c, int * totalRes)
405 root = cJSON_Parse((char *)(resJSONPayload));
409 OC_LOG(ERROR, TAG, "JSON Parsing Error");
410 return OC_STACK_INVALID_JSON;
413 oc = cJSON_GetObjectItem(root,"oic");
416 OC_LOG(ERROR, TAG, "Invalid JSON : Missing oc object");
417 return OC_STACK_INVALID_JSON;
420 * totalRes = cJSON_GetArraySize(oc);
422 if(oc->type == cJSON_Array)
424 cJSON * resource = cJSON_GetArrayItem(oc, 0);
428 return OC_STACK_INVALID_JSON;
431 if (cJSON_GetObjectItem(resource, "sid"))
433 char * sid = cJSON_GetObjectItem(resource, "sid")->valuestring;
434 if((* sid_c = (char *)OICCalloc(1, strlen (sid) + 1)))
436 memcpy(* sid_c, sid, strlen(sid) + 1);
440 OC_LOG(ERROR, TAG, "Memory not allocated to sid");
441 return OC_STACK_NO_MEMORY;
446 OC_LOG(ERROR, TAG, "Invalid JSON : Missing sid object");
447 return OC_STACK_INVALID_JSON;
450 if(!(* uri_c = (char ** )OICMalloc ((* totalRes) * sizeof(char *))))
452 OC_LOG(ERROR, TAG, "Memory not allocated to uri_c array");
453 return OC_STACK_NO_MEMORY;
460 if (cJSON_GetObjectItem(resource, "href"))
462 char *uri= cJSON_GetObjectItem(resource, "href")->valuestring;
463 if(((*uri_c)[i] = (char *)OICCalloc(1, strlen (uri) + 1)))
465 memcpy((*uri_c)[i], uri, strlen(uri) + 1);
469 OC_LOG(ERROR, TAG, "Memory not allocated to uri");
470 return OC_STACK_NO_MEMORY;
473 if(i >= (* totalRes))
475 resource = cJSON_GetArrayItem(oc, i);
479 OC_LOG(ERROR, TAG, "Invalid JSON : Missing uri object");
480 return OC_STACK_INVALID_JSON;
486 return OC_STACK_INVALID_JSON;
487 OC_LOG(ERROR, TAG, "Invalid JSON : oc object type is not an array");
496 case TEST_DISCOVER_REQ:
498 case TEST_NON_CON_OP:
499 InitGetRequest(OC_LOW_QOS);
500 InitPutRequest(OC_LOW_QOS);
501 InitPostRequest(OC_LOW_QOS);
504 InitGetRequest(OC_HIGH_QOS);
505 InitPutRequest(OC_HIGH_QOS);
506 InitPostRequest(OC_HIGH_QOS);
515 void collectUniqueResource(const OCClientResponse * clientResponse)
522 if(parseJSON(clientResponse->resJSONPayload, & sid, & uri, &totalRes)
525 OC_LOG(ERROR, TAG, "Error while parsing JSON payload in OCClientResponse");
528 for (i = 0; i < totalRes; i++)
537 for(i = 0; i < totalRes; i++)
539 if(insertResource(sid, uri[i], clientResponse) == 1)
541 printf("%s%s%s%s\n",sid, ":", uri[i], " is new");
547 printf("%s%s%s%s\n\n",sid, ":", uri[i], " has been seen before");
552 for (i = 0; i < totalRes; i++)
559 /* This function searches for the resource(sid:uri) in the ResourceList.
560 * If the Resource is found in the list then it returns 0 else insert
561 * the resource to front of the list and returns 1.
563 int insertResource(const char * sid, char const * uri,
564 const OCClientResponse * clientResponse)
566 ResourceNode * iter = resourceList;
567 char * sid_cpy = OICStrdup(sid);
568 char * uri_cpy = OICStrdup(uri);
570 //Checking if the resource(sid:uri) is new
573 if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
585 //Creating new ResourceNode
586 if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
590 iter->ip = getIPAddr(clientResponse);
591 iter->port = getPort(clientResponse);
592 iter->connType = clientResponse->connType;
597 OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
603 //Adding new ResourceNode to front of the ResourceList
610 iter->next = resourceList;
616 void printResourceList()
620 OC_LOG(INFO, TAG, "Resource List: ");
623 OC_LOG(INFO, TAG, "*****************************************************");
624 OC_LOG_V(INFO, TAG, "sid = %s",iter->sid);
625 OC_LOG_V(INFO, TAG, "uri = %s", iter->uri);
626 OC_LOG_V(INFO, TAG, "ip = %s", iter->ip);
627 OC_LOG_V(INFO, TAG, "port = %s", iter->port);
628 switch (iter->connType & CT_MASK_ADAPTER)
631 OC_LOG(INFO, TAG, "connType = Default (IPv4)");
633 case OC_ADAPTER_GATT_BTLE:
634 OC_LOG(INFO, TAG, "connType = BLE");
636 case OC_ADAPTER_RFCOMM_BTEDR:
637 OC_LOG(INFO, TAG, "connType = BT");
640 OC_LOG(INFO, TAG, "connType = Invalid connType");
643 OC_LOG(INFO, TAG, "*****************************************************");
648 void freeResourceList()
650 OC_LOG(INFO, TAG, "Freeing ResourceNode List");
656 resourceList = resourceList->next;
657 OICFree((void *)temp->sid);
658 OICFree((void *)temp->uri);
659 OICFree((void *)temp->ip);
660 OICFree((void *)temp->port);
666 int main(int argc, char* argv[])
670 while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
675 UNICAST_DISCOVERY = atoi(optarg);
678 TEST_CASE = atoi(optarg);
682 CONNECTIVITY = atoi(optarg);
690 if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
691 (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) ||
692 (CONNECTIVITY < CT_ADAPTER_DEFAULT || CONNECTIVITY >= MAX_CT))
698 /* Initialize OCStack*/
699 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
701 OC_LOG(ERROR, TAG, "OCStack init error");
705 if(CONNECTIVITY == CT_ADAPTER_DEFAULT || CONNECTIVITY == CT_IP)
707 OC_CONNTYPE = CT_ADAPTER_IP;//CT_DEFAULT;
711 OC_LOG(INFO, TAG, "Default Connectivity type selected");
717 // Break from loop with Ctrl+C
718 signal(SIGINT, handleSigInt);
722 if (OCProcess() != OC_STACK_OK)
724 OC_LOG(ERROR, TAG, "OCStack process error");
731 OC_LOG(INFO, TAG, "Exiting occlient main loop...");
732 if (OCStop() != OC_STACK_OK)
734 OC_LOG(ERROR, TAG, "OCStack stop error");