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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
31 #include "occlientbasicops.h"
32 #include "ocpayload.h"
33 #include "oic_malloc.h"
34 #include "oic_string.h"
36 #define MAX_IP_ADDR_ST_SZ 16 //string size of "155.255.255.255" (15 + 1)
37 #define MAX_PORT_ST_SZ 6 //string size of "65535" (5 + 1)
39 static int IPV4_ADDR_SIZE = 24;
40 static int UNICAST_DISCOVERY = 0;
41 static int TEST_CASE = 0;
42 static int CONNECTIVITY = 0;
44 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s/oic/res";
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 OCPayload* putPayload()
67 OCRepPayload* payload = OCRepPayloadCreate();
71 std::cout << "Failed to create put payload object"<<std::endl;
75 OCRepPayloadSetPropInt(payload, "power", 15);
76 OCRepPayloadSetPropBool(payload, "state", true);
78 return (OCPayload*) payload;
81 static void PrintUsage()
83 OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
84 OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
85 OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
86 OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
87 " Initiate Nonconfirmable Get/Put/Post Requests");
88 OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
89 "Confirmable Get/Put/Post Requests");
90 OC_LOG(INFO, TAG, "-c 0 : Default auto-selection");
91 OC_LOG(INFO, TAG, "-c 1 : IP Connectivity Type");
95 * Returns the first resource in the list
97 const ResourceNode * getResource()
102 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
103 OCConnectivityType connType, OCQualityOfService qos,
104 OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
107 OCCallbackData cbData;
110 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
113 ret = OCDoResource(NULL, method, query.str().c_str(), 0,
114 (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload() : NULL,
115 connType, qos, &cbData, options, numOptions);
117 if (ret != OC_STACK_OK)
119 OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
126 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle /*handle*/,
127 OCClientResponse * clientResponse)
129 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
131 OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
135 OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
140 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
141 OC_LOG(INFO, TAG, PCF("=============> Put Response"));
145 OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
147 return OC_STACK_DELETE_TRANSACTION;
150 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle /*handle*/,
151 OCClientResponse *clientResponse)
153 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
155 OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
159 OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
164 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
165 OC_LOG(INFO, TAG, PCF("=============> Post Response"));
169 OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
172 return OC_STACK_DELETE_TRANSACTION;
175 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle /*handle*/,
176 OCClientResponse * clientResponse)
178 if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
180 OC_LOG(INFO, TAG, "<====Callback Context for GET received successfully====>");
184 OC_LOG(ERROR, TAG, "<====Callback Context for GET fail====>");
189 OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
190 OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
191 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
192 OC_LOG(INFO, TAG, PCF("=============> Get Response"));
194 if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0 )
196 OC_LOG (INFO, TAG, "Received vendor specific options");
198 OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
199 for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
201 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
203 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
204 ((OCHeaderOption)rcvdOptions[i]).optionID );
206 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
207 MAX_HEADER_OPTION_DATA_LENGTH);
214 OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
216 return OC_STACK_DELETE_TRANSACTION;
220 * This is a function called back when a device is discovered
222 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle /*handle*/,
223 OCClientResponse * clientResponse)
225 if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
227 OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
228 "received successfully====>");
232 OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
238 "Device =============> Discovered @ %s:%d",
239 clientResponse->devAddr.addr,
240 clientResponse->devAddr.port);
241 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
243 collectUniqueResource(clientResponse);
247 OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
249 return (UNICAST_DISCOVERY) ?
250 OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
253 int InitPutRequest(OCQualityOfService qos)
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 PUT request\n");
264 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
265 OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
267 return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
268 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
272 int InitPostRequest(OCQualityOfService qos)
274 OCStackResult result;
275 std::ostringstream query;
276 //Get most recently inserted resource
277 const ResourceNode * resource = getResource();
281 OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
285 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
286 OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
288 // First POST operation (to create an LED instance)
289 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
290 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
292 if (OC_STACK_OK != result)
294 // Error can happen if for example, network connectivity is down
295 OC_LOG(ERROR, TAG, "First POST call did not succeed");
298 // Second POST operation (to create an LED instance)
299 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
300 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
302 if (OC_STACK_OK != result)
304 OC_LOG(ERROR, TAG, "Second POST call did not succeed");
307 // This POST operation will update the original resourced /a/led
308 return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
309 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
310 postReqCB, NULL, 0));
313 int InitGetRequest(OCQualityOfService qos)
315 std::ostringstream query;
316 //Get most recently inserted resource
317 const ResourceNode * resource = getResource();
321 OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
324 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
325 OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
327 return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
328 (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
334 OCCallbackData cbData;
335 /* Start a discovery query*/
336 char szQueryUri[64] = {};
337 if (UNICAST_DISCOVERY)
339 char ipv4addr[IPV4_ADDR_SIZE];
340 OC_LOG(INFO, TAG, "Enter IP address with port of the Server hosting resource"\
341 "(Ex: 192.168.0.15:1234) ");
343 if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
345 //Strip newline char from ipv4addr
346 StripNewLineChar(ipv4addr);
347 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
351 OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
352 return OC_STACK_INVALID_PARAM;
357 OICStrcpy(szQueryUri, sizeof(szQueryUri), MULTICAST_RESOURCE_DISCOVERY_QUERY);
359 cbData.cb = discoveryReqCB;
360 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
362 if (UNICAST_DISCOVERY)
364 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
365 OC_LOW_QOS, &cbData, NULL, 0);
369 ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT,
370 OC_LOW_QOS, &cbData, NULL, 0);
373 if (ret != OC_STACK_OK)
375 OC_LOG(ERROR, TAG, "OCStack resource error");
380 const char *getIPAddr(const OCClientResponse *clientResponse)
387 const OCDevAddr *devAddr = &clientResponse->devAddr;
388 char *ipaddr = (char *) OICCalloc(1, strlen(devAddr->addr) +1);
391 snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%s", devAddr->addr);
395 OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
400 const char *getPort(const OCClientResponse *clientResponse)
408 if((port = (char *)OICCalloc(1, MAX_PORT_ST_SZ)))
410 snprintf(port, MAX_PORT_ST_SZ, "%d", clientResponse->devAddr.port);
414 OC_LOG(ERROR, TAG, "Memory not allocated to port");
423 case TEST_DISCOVER_REQ:
425 case TEST_NON_CON_OP:
426 InitGetRequest(OC_LOW_QOS);
427 InitPutRequest(OC_LOW_QOS);
428 InitPostRequest(OC_LOW_QOS);
431 InitGetRequest(OC_HIGH_QOS);
432 InitPutRequest(OC_HIGH_QOS);
433 InitPostRequest(OC_HIGH_QOS);
442 void collectUniqueResource(const OCClientResponse * clientResponse)
444 OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
445 char sidStr[UUID_LENGTH];
449 int ret = snprintf(sidStr, UUID_LENGTH,
450 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
451 res->sid[0], res->sid[1], res->sid[2], res->sid[3],
452 res->sid[4], res->sid[5], res->sid[6], res->sid[7],
453 res->sid[8], res->sid[9], res->sid[10], res->sid[11],
454 res->sid[12], res->sid[13], res->sid[14], res->sid[15]
457 if (ret == UUID_LENGTH - 1)
459 if(insertResource(sidStr, res->uri, clientResponse) == 1)
461 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is new");
466 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is old");
471 OC_LOG(ERROR, TAG, "Could Not Retrieve the Server ID");
478 /* This function searches for the resource(sid:uri) in the ResourceList.
479 * If the Resource is found in the list then it returns 0 else insert
480 * the resource to front of the list and returns 1.
482 int insertResource(const char * sid, char const * uri,
483 const OCClientResponse * clientResponse)
485 ResourceNode * iter = resourceList;
486 char * sid_cpy = OICStrdup(sid);
487 char * uri_cpy = OICStrdup(uri);
489 //Checking if the resource(sid:uri) is new
492 if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
504 //Creating new ResourceNode
505 if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
509 iter->ip = getIPAddr(clientResponse);
510 iter->port = getPort(clientResponse);
511 iter->connType = clientResponse->connType;
516 OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
522 //Adding new ResourceNode to front of the ResourceList
529 iter->next = resourceList;
535 void printResourceList()
539 OC_LOG(INFO, TAG, "Resource List: ");
542 OC_LOG(INFO, TAG, "*****************************************************");
543 OC_LOG_V(INFO, TAG, "sid = %s",iter->sid);
544 OC_LOG_V(INFO, TAG, "uri = %s", iter->uri);
545 OC_LOG_V(INFO, TAG, "ip = %s", iter->ip);
546 OC_LOG_V(INFO, TAG, "port = %s", iter->port);
547 switch (iter->connType & CT_MASK_ADAPTER)
550 OC_LOG(INFO, TAG, "connType = Default (IPv4)");
552 case OC_ADAPTER_GATT_BTLE:
553 OC_LOG(INFO, TAG, "connType = BLE");
555 case OC_ADAPTER_RFCOMM_BTEDR:
556 OC_LOG(INFO, TAG, "connType = BT");
559 OC_LOG(INFO, TAG, "connType = Invalid connType");
562 OC_LOG(INFO, TAG, "*****************************************************");
567 void freeResourceList()
569 OC_LOG(INFO, TAG, "Freeing ResourceNode List");
575 resourceList = resourceList->next;
576 OICFree((void *)temp->sid);
577 OICFree((void *)temp->uri);
578 OICFree((void *)temp->ip);
579 OICFree((void *)temp->port);
585 int main(int argc, char* argv[])
589 while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
594 UNICAST_DISCOVERY = atoi(optarg);
597 TEST_CASE = atoi(optarg);
601 CONNECTIVITY = atoi(optarg);
609 if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
610 (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) ||
611 (CONNECTIVITY < CT_ADAPTER_DEFAULT || CONNECTIVITY >= MAX_CT))
617 /* Initialize OCStack*/
618 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
620 OC_LOG(ERROR, TAG, "OCStack init error");
624 if(CONNECTIVITY == CT_ADAPTER_DEFAULT || CONNECTIVITY == CT_IP)
626 OC_CONNTYPE = CT_ADAPTER_IP;//CT_DEFAULT;
630 OC_LOG(INFO, TAG, "Default Connectivity type selected");
636 // Break from loop with Ctrl+C
637 signal(SIGINT, handleSigInt);
641 if (OCProcess() != OC_STACK_OK)
643 OC_LOG(ERROR, TAG, "OCStack process error");
650 OC_LOG(INFO, TAG, "Exiting occlient main loop...");
651 if (OCStop() != OC_STACK_OK)
653 OC_LOG(ERROR, TAG, "OCStack stop error");