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 = 16;
39 static int UNICAST_DISCOVERY = 0;
40 static int TEST_CASE = 0;
42 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s:6298/oic/res";
43 static std::string putPayload = "{\"oic\":[{\"rep\":{\"power\":15,\"state\":true}}]}";
45 //The following variable determines the interface protocol (IPv4, IPv6, etc)
46 //to be used for sending unicast messages. Default set to IPv4.
47 static OCConnectivityType OC_CONNTYPE = OC_IPV4;
48 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
52 struct ResourceNode *resourceList;
54 * SIGINT handler: set gQuitFlag to 1 for graceful termination
56 void handleSigInt(int signum)
64 static void PrintUsage()
66 OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
67 OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
68 OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
69 OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
70 " Initiate Nonconfirmable Get/Put/Post Requests");
71 OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
72 "Confirmable Get/Put/Post Requests");
73 OC_LOG(INFO, TAG, "-c <0|1> : IPv4/IPv6 (IPv6 not currently supported)");
74 OC_LOG(INFO, TAG, "Default connectivityType IPv4");
78 * Returns the first resource in the list
80 const ResourceNode * getResource()
85 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
86 OCConnectivityType connType, OCQualityOfService qos,
87 OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
90 OCCallbackData cbData;
93 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
96 ret = OCDoResource(NULL, method, query.str().c_str(), 0,
97 (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload.c_str() : NULL,
98 connType, qos, &cbData, options, numOptions);
100 if (ret != OC_STACK_OK)
102 OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
109 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle,
110 OCClientResponse * clientResponse)
112 uint8_t remoteIpAddr[4];
113 uint16_t remotePortNu;
115 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
117 OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
121 OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
126 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
127 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
128 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
130 OC_LOG_V(INFO, TAG,"PUT Response: %s \nFrom %d.%d.%d.%d:%d\n",
131 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
132 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
136 OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
138 return OC_STACK_DELETE_TRANSACTION;
141 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle,
142 OCClientResponse *clientResponse)
144 uint8_t remoteIpAddr[4];
145 uint16_t remotePortNu;
147 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
149 OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
153 OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
158 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
159 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
160 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
162 OC_LOG_V(INFO, TAG,"POST Response: %s \nFrom %d.%d.%d.%d:%d\n",
163 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
164 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
168 OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
171 return OC_STACK_DELETE_TRANSACTION;
174 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
175 OCClientResponse * clientResponse)
177 uint8_t remoteIpAddr[4];
178 uint16_t remotePortNu;
180 if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
182 OC_LOG(INFO, TAG, "<====Callback Context for GET received successfully====>");
186 OC_LOG(ERROR, TAG, "<====Callback Context for GET fail====>");
191 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr, remoteIpAddr + 1,
192 remoteIpAddr + 2, remoteIpAddr + 3);
193 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
195 OC_LOG_V(INFO, TAG,"Get Response: %s \nFrom %d.%d.%d.%d:%d\n",
196 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
197 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
199 if (clientResponse->rcvdVendorSpecificHeaderOptions
200 && clientResponse->numRcvdVendorSpecificHeaderOptions)
202 OC_LOG (INFO, TAG, "Received vendor specific options");
204 OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
205 for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
207 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
209 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
210 ((OCHeaderOption)rcvdOptions[i]).optionID );
212 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
213 MAX_HEADER_OPTION_DATA_LENGTH);
220 OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
222 return OC_STACK_DELETE_TRANSACTION;
226 * This is a function called back when a device is discovered
228 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
229 OCClientResponse * clientResponse)
231 uint8_t remoteIpAddr[4];
232 uint16_t remotePortNu;
233 if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
235 OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
236 "received successfully====>");
240 OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
245 OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
246 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
247 OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
250 "Device Discovered %s \n @ %d.%d.%d.%d:%d\n",
251 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
252 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
254 collectUniqueResource(clientResponse);
258 OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
260 return (UNICAST_DISCOVERY) ?
261 OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
264 int InitPutRequest(OCQualityOfService qos)
266 std::ostringstream query;
267 //Get most recently inserted resource
268 const ResourceNode * resource = getResource();
272 OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
275 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
276 OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
278 return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
279 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
283 int InitPostRequest(OCQualityOfService qos)
285 OCStackResult result;
286 std::ostringstream query;
287 //Get most recently inserted resource
288 const ResourceNode * resource = getResource();
292 OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
296 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
297 OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
299 // First POST operation (to create an LED instance)
300 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
301 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
303 if (OC_STACK_OK != result)
305 // Error can happen if for example, network connectivity is down
306 OC_LOG(ERROR, TAG, "First POST call did not succeed");
309 // Second POST operation (to create an LED instance)
310 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
311 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
313 if (OC_STACK_OK != result)
315 OC_LOG(ERROR, TAG, "Second POST call did not succeed");
318 // This POST operation will update the original resourced /a/led
319 return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
320 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
321 postReqCB, NULL, 0));
324 int InitGetRequest(OCQualityOfService qos)
326 std::ostringstream query;
327 //Get most recently inserted resource
328 const ResourceNode * resource = getResource();
332 OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
335 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
336 OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
338 return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
339 (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
345 OCCallbackData cbData;
346 /* Start a discovery query*/
347 char szQueryUri[64] = {};
348 if (UNICAST_DISCOVERY)
350 char ipv4addr[IPV4_ADDR_SIZE];
351 printf("Enter IPv4 address of the Server hosting "
352 "resource (Ex: 192.168.0.15)\n");
353 if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
355 //Strip newline char from ipv4addr
356 StripNewLineChar(ipv4addr);
357 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
361 OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
362 return OC_STACK_INVALID_PARAM;
367 strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
369 cbData.cb = discoveryReqCB;
370 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
372 if (UNICAST_DISCOVERY)
374 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
375 OC_LOW_QOS, &cbData, NULL, 0);
379 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, (OC_ALL),
380 OC_LOW_QOS, &cbData, NULL, 0);
383 if (ret != OC_STACK_OK)
385 OC_LOG(ERROR, TAG, "OCStack resource error");
392 const char * getIPAddr(const OCClientResponse * clientResponse)
395 if(!clientResponse || 0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d))
400 char * ipaddr = NULL;
401 if((ipaddr = (char *) OICCalloc(1, MAX_IP_ADDR_ST_SZ)))
403 snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%d.%d.%d.%d", a,b,c,d);
407 OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
412 const char * getPort(const OCClientResponse * clientResponse)
415 if(!clientResponse || 0 != OCDevAddrToPort(clientResponse->addr, &p) )
421 if((port = (char *) OICCalloc(1, MAX_PORT_ST_SZ)))
423 snprintf(port, MAX_PORT_ST_SZ, "%d", p);
427 OC_LOG(ERROR, TAG, "Memory not allocated to port");
432 int parseJSON(const char * resJSONPayload, char ** sid_c,
433 char *** uri_c, int * totalRes)
438 root = cJSON_Parse((char *)(resJSONPayload));
442 OC_LOG(ERROR, TAG, "JSON Parsing Error");
443 return OC_STACK_INVALID_JSON;
446 oc = cJSON_GetObjectItem(root,"oic");
449 OC_LOG(ERROR, TAG, "Invalid JSON : Missing oc object");
450 return OC_STACK_INVALID_JSON;
453 * totalRes = cJSON_GetArraySize(oc);
455 if(oc->type == cJSON_Array)
457 cJSON * resource = cJSON_GetArrayItem(oc, 0);
461 return OC_STACK_INVALID_JSON;
464 if (cJSON_GetObjectItem(resource, "sid"))
466 char * sid = cJSON_GetObjectItem(resource, "sid")->valuestring;
467 if((* sid_c = (char *)OICCalloc(1, strlen (sid) + 1)))
469 memcpy(* sid_c, sid, strlen(sid) + 1);
473 OC_LOG(ERROR, TAG, "Memory not allocated to sid");
474 return OC_STACK_NO_MEMORY;
479 OC_LOG(ERROR, TAG, "Invalid JSON : Missing sid object");
480 return OC_STACK_INVALID_JSON;
483 if(!(* uri_c = (char ** )OICMalloc ((* totalRes) * sizeof(char *))))
485 OC_LOG(ERROR, TAG, "Memory not allocated to uri_c array");
486 return OC_STACK_NO_MEMORY;
493 if (cJSON_GetObjectItem(resource, "href"))
495 char *uri= cJSON_GetObjectItem(resource, "href")->valuestring;
496 if(((*uri_c)[i] = (char *)OICCalloc(1, strlen (uri) + 1)))
498 memcpy((*uri_c)[i], uri, strlen(uri) + 1);
502 OC_LOG(ERROR, TAG, "Memory not allocated to uri");
503 return OC_STACK_NO_MEMORY;
506 if(i >= (* totalRes))
508 resource = cJSON_GetArrayItem(oc, i);
512 OC_LOG(ERROR, TAG, "Invalid JSON : Missing uri object");
513 return OC_STACK_INVALID_JSON;
519 return OC_STACK_INVALID_JSON;
520 OC_LOG(ERROR, TAG, "Invalid JSON : oc object type is not an array");
530 case TEST_DISCOVER_REQ:
532 case TEST_NON_CON_OP:
533 InitGetRequest(OC_LOW_QOS);
534 InitPutRequest(OC_LOW_QOS);
535 InitPostRequest(OC_LOW_QOS);
538 InitGetRequest(OC_HIGH_QOS);
539 InitPutRequest(OC_HIGH_QOS);
540 InitPostRequest(OC_HIGH_QOS);
550 void collectUniqueResource(const OCClientResponse * clientResponse)
557 if(parseJSON(clientResponse->resJSONPayload, & sid, & uri, &totalRes)
560 OC_LOG(ERROR, TAG, "Error while parsing JSON payload in OCClientResponse");
563 for (i = 0; i < totalRes; i++)
572 for(i = 0; i < totalRes; i++)
574 if(insertResource(sid, uri[i], clientResponse) == 1)
576 printf("%s%s%s%s\n",sid, ":", uri[i], " is new");
582 printf("%s%s%s%s\n\n",sid, ":", uri[i], " has been seen before");
587 for (i = 0; i < totalRes; i++)
594 /* This function searches for the resource(sid:uri) in the ResourceList.
595 * If the Resource is found in the list then it returns 0 else insert
596 * the resource to front of the list and returns 1.
598 int insertResource(const char * sid, char const * uri,
599 const OCClientResponse * clientResponse)
601 ResourceNode * iter = resourceList;
602 char * sid_cpy = OICStrdup(sid);
603 char * uri_cpy = OICStrdup(uri);
605 //Checking if the resource(sid:uri) is new
608 if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
620 //Creating new ResourceNode
621 if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
625 iter->ip = getIPAddr(clientResponse);
626 iter->port = getPort(clientResponse);
627 iter->connType = clientResponse->connType;
632 OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
638 //Adding new ResourceNode to front of the ResourceList
645 iter->next = resourceList;
651 void printResourceList()
655 printf("\nResource List\n");
658 printf("*****************************************************\n");
659 printf("sid = %s \n",iter->sid);
660 printf("uri = %s\n", iter->uri);
661 printf("ip = %s\n", iter->ip);
662 printf("port = %s\n", iter->port);
663 switch (iter->connType)
666 printf("connType = %s\n","IPv4");
669 // TODO: Allow IPv6 when support is added
670 printf("IPv6 not currently supported, default to IPv4\n");
671 //printf("connType = %s\n","IPv6");
672 printf("connType = %s\n","IPv4");
675 printf("connType = %s\n","BLE");
678 printf("connType = %s\n","BT");
682 printf("connType = %s\n","Invalid connType");
685 printf("*****************************************************\n");
690 void freeResourceList()
692 OC_LOG(INFO, TAG, "Freeing ResourceNode List");
697 resourceList = resourceList->next;
698 OICFree((void *)temp->sid);
699 OICFree((void *)temp->uri);
700 OICFree((void *)temp->ip);
701 OICFree((void *)temp->port);
707 int main(int argc, char* argv[])
711 while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
716 UNICAST_DISCOVERY = atoi(optarg);
719 TEST_CASE = atoi(optarg);
722 // TODO: re-enable IPv4/IPv6 command line selection when IPv6 is supported
723 // OC_CONNTYPE = OCConnectivityType(atoi(optarg));
724 OC_CONNTYPE = OC_IPV4;
725 OC_LOG(INFO, TAG, "Using default IPv4, IPv6 not currently supported.");
733 if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
734 (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
740 /* Initialize OCStack*/
741 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
743 OC_LOG(ERROR, TAG, "OCStack init error");
749 // Break from loop with Ctrl+C
750 signal(SIGINT, handleSigInt);
754 if (OCProcess() != OC_STACK_OK)
756 OC_LOG(ERROR, TAG, "OCStack process error");
763 OC_LOG(INFO, TAG, "Exiting occlient main loop...");
764 if (OCStop() != OC_STACK_OK)
766 OC_LOG(ERROR, TAG, "OCStack stop error");