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 "payload_logging.h"
34 #include "oic_malloc.h"
35 #include "oic_string.h"
37 #define MAX_IP_ADDR_ST_SZ 16 //string size of "155.255.255.255" (15 + 1)
38 #define MAX_PORT_ST_SZ 6 //string size of "65535" (5 + 1)
40 static int IPV4_ADDR_SIZE = 24;
41 static int UNICAST_DISCOVERY = 0;
42 static int TEST_CASE = 0;
43 static int CONNECTIVITY = 0;
45 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s/oic/res";
47 //The following variable determines the interface protocol (IP, etc)
48 //to be used for sending unicast messages. Default set to IP.
49 static OCConnectivityType OC_CONNTYPE = CT_ADAPTER_IP;
50 static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
54 struct ResourceNode *resourceList;
56 * SIGINT handler: set gQuitFlag to 1 for graceful termination
58 void handleSigInt(int signum)
66 OCPayload* putPayload()
68 OCRepPayload* payload = OCRepPayloadCreate();
72 std::cout << "Failed to create put payload object"<<std::endl;
76 OCRepPayloadSetPropInt(payload, "power", 15);
77 OCRepPayloadSetPropBool(payload, "state", true);
79 return (OCPayload*) payload;
82 static void PrintUsage()
84 OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
85 OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
86 OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
87 OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
88 " Initiate Nonconfirmable Get/Put/Post Requests");
89 OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
90 "Confirmable Get/Put/Post Requests");
91 OC_LOG(INFO, TAG, "-c 0 : Default auto-selection");
92 OC_LOG(INFO, TAG, "-c 1 : IP Connectivity Type");
96 * Returns the first resource in the list
98 const ResourceNode * getResource()
103 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
104 OCConnectivityType connType, OCQualityOfService qos,
105 OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
108 OCCallbackData cbData;
111 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
114 ret = OCDoResource(NULL, method, query.str().c_str(), 0,
115 (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload() : NULL,
116 connType, qos, &cbData, options, numOptions);
118 if (ret != OC_STACK_OK)
120 OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
127 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle /*handle*/,
128 OCClientResponse * clientResponse)
130 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
132 OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
136 OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
141 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
142 OC_LOG(INFO, TAG, PCF("=============> Put Response"));
146 OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
148 return OC_STACK_DELETE_TRANSACTION;
151 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle /*handle*/,
152 OCClientResponse *clientResponse)
154 if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
156 OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
160 OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
165 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
166 OC_LOG(INFO, TAG, PCF("=============> Post Response"));
170 OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
173 return OC_STACK_DELETE_TRANSACTION;
176 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle /*handle*/,
177 OCClientResponse * clientResponse)
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 OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
191 OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
192 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
193 OC_LOG(INFO, TAG, PCF("=============> Get Response"));
195 if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0 )
197 OC_LOG (INFO, TAG, "Received vendor specific options");
199 OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
200 for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
202 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
204 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
205 ((OCHeaderOption)rcvdOptions[i]).optionID );
207 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
208 MAX_HEADER_OPTION_DATA_LENGTH);
215 OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
217 return OC_STACK_DELETE_TRANSACTION;
221 * This is a function called back when a device is discovered
223 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle /*handle*/,
224 OCClientResponse * clientResponse)
226 if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
228 OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
229 "received successfully====>");
233 OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
239 "Device =============> Discovered @ %s:%d",
240 clientResponse->devAddr.addr,
241 clientResponse->devAddr.port);
242 OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
244 collectUniqueResource(clientResponse);
248 OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
250 return (UNICAST_DISCOVERY) ?
251 OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
254 int InitPutRequest(OCQualityOfService qos)
256 std::ostringstream query;
257 //Get most recently inserted resource
258 const ResourceNode * resource = getResource();
262 OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
265 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
266 OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
268 return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
269 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
273 int InitPostRequest(OCQualityOfService qos)
275 OCStackResult result;
276 std::ostringstream query;
277 //Get most recently inserted resource
278 const ResourceNode * resource = getResource();
282 OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
286 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
287 OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
289 // First POST operation (to create an LED instance)
290 result = InvokeOCDoResource(query, OC_REST_POST, resource->connType,
291 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
293 if (OC_STACK_OK != result)
295 // Error can happen if for example, network connectivity is down
296 OC_LOG(ERROR, TAG, "First POST call did not succeed");
299 // Second 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 OC_LOG(ERROR, TAG, "Second POST call did not succeed");
308 // This POST operation will update the original resourced /a/led
309 return (InvokeOCDoResource(query, OC_REST_POST,resource->connType,
310 ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
311 postReqCB, NULL, 0));
314 int InitGetRequest(OCQualityOfService qos)
316 std::ostringstream query;
317 //Get most recently inserted resource
318 const ResourceNode * resource = getResource();
322 OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
325 query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
326 OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
328 return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
329 (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
335 OCCallbackData cbData;
336 /* Start a discovery query*/
337 char szQueryUri[64] = {};
338 if (UNICAST_DISCOVERY)
340 char ipv4addr[IPV4_ADDR_SIZE];
341 OC_LOG(INFO, TAG, "Enter IP address with port of the Server hosting resource"\
342 "(Ex: 192.168.0.15:1234) ");
344 if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
346 //Strip newline char from ipv4addr
347 StripNewLineChar(ipv4addr);
348 snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
352 OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
353 return OC_STACK_INVALID_PARAM;
358 OICStrcpy(szQueryUri, sizeof(szQueryUri), MULTICAST_RESOURCE_DISCOVERY_QUERY);
360 cbData.cb = discoveryReqCB;
361 cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
363 if (UNICAST_DISCOVERY)
365 ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
366 OC_LOW_QOS, &cbData, NULL, 0);
370 ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT,
371 OC_LOW_QOS, &cbData, NULL, 0);
374 if (ret != OC_STACK_OK)
376 OC_LOG(ERROR, TAG, "OCStack resource error");
381 const char *getIPAddr(const OCClientResponse *clientResponse)
388 const OCDevAddr *devAddr = &clientResponse->devAddr;
389 char *ipaddr = (char *) OICCalloc(1, strlen(devAddr->addr) +1);
392 snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%s", devAddr->addr);
396 OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
401 const char *getPort(const OCClientResponse *clientResponse)
409 if((port = (char *)OICCalloc(1, MAX_PORT_ST_SZ)))
411 snprintf(port, MAX_PORT_ST_SZ, "%d", clientResponse->devAddr.port);
415 OC_LOG(ERROR, TAG, "Memory not allocated to port");
424 case TEST_DISCOVER_REQ:
426 case TEST_NON_CON_OP:
427 InitGetRequest(OC_LOW_QOS);
428 InitPutRequest(OC_LOW_QOS);
429 InitPostRequest(OC_LOW_QOS);
432 InitGetRequest(OC_HIGH_QOS);
433 InitPutRequest(OC_HIGH_QOS);
434 InitPostRequest(OC_HIGH_QOS);
443 void collectUniqueResource(const OCClientResponse * clientResponse)
445 OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
446 char sidStr[UUID_LENGTH];
450 int ret = snprintf(sidStr, UUID_LENGTH,
451 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
452 res->sid[0], res->sid[1], res->sid[2], res->sid[3],
453 res->sid[4], res->sid[5], res->sid[6], res->sid[7],
454 res->sid[8], res->sid[9], res->sid[10], res->sid[11],
455 res->sid[12], res->sid[13], res->sid[14], res->sid[15]
458 if (ret == UUID_LENGTH - 1)
460 if(insertResource(sidStr, res->uri, clientResponse) == 1)
462 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is new");
467 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is old");
472 OC_LOG(ERROR, TAG, "Could Not Retrieve the Server ID");
479 /* This function searches for the resource(sid:uri) in the ResourceList.
480 * If the Resource is found in the list then it returns 0 else insert
481 * the resource to front of the list and returns 1.
483 int insertResource(const char * sid, char const * uri,
484 const OCClientResponse * clientResponse)
486 ResourceNode * iter = resourceList;
487 char * sid_cpy = OICStrdup(sid);
488 char * uri_cpy = OICStrdup(uri);
490 //Checking if the resource(sid:uri) is new
493 if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
505 //Creating new ResourceNode
506 if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
510 iter->ip = getIPAddr(clientResponse);
511 iter->port = getPort(clientResponse);
512 iter->connType = clientResponse->connType;
517 OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
523 //Adding new ResourceNode to front of the ResourceList
530 iter->next = resourceList;
536 void printResourceList()
540 OC_LOG(INFO, TAG, "Resource List: ");
543 OC_LOG(INFO, TAG, "*****************************************************");
544 OC_LOG_V(INFO, TAG, "sid = %s",iter->sid);
545 OC_LOG_V(INFO, TAG, "uri = %s", iter->uri);
546 OC_LOG_V(INFO, TAG, "ip = %s", iter->ip);
547 OC_LOG_V(INFO, TAG, "port = %s", iter->port);
548 switch (iter->connType & CT_MASK_ADAPTER)
551 OC_LOG(INFO, TAG, "connType = Default (IPv4)");
553 case OC_ADAPTER_GATT_BTLE:
554 OC_LOG(INFO, TAG, "connType = BLE");
556 case OC_ADAPTER_RFCOMM_BTEDR:
557 OC_LOG(INFO, TAG, "connType = BT");
560 OC_LOG(INFO, TAG, "connType = Invalid connType");
563 OC_LOG(INFO, TAG, "*****************************************************");
568 void freeResourceList()
570 OC_LOG(INFO, TAG, "Freeing ResourceNode List");
576 resourceList = resourceList->next;
577 OICFree((void *)temp->sid);
578 OICFree((void *)temp->uri);
579 OICFree((void *)temp->ip);
580 OICFree((void *)temp->port);
586 int main(int argc, char* argv[])
590 while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
595 UNICAST_DISCOVERY = atoi(optarg);
598 TEST_CASE = atoi(optarg);
602 CONNECTIVITY = atoi(optarg);
610 if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
611 (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) ||
612 (CONNECTIVITY < CT_ADAPTER_DEFAULT || CONNECTIVITY >= MAX_CT))
618 /* Initialize OCStack*/
619 if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
621 OC_LOG(ERROR, TAG, "OCStack init error");
625 if(CONNECTIVITY == CT_ADAPTER_DEFAULT || CONNECTIVITY == CT_IP)
627 OC_CONNTYPE = CT_ADAPTER_IP;//CT_DEFAULT;
631 OC_LOG(INFO, TAG, "Default Connectivity type selected");
637 // Break from loop with Ctrl+C
638 signal(SIGINT, handleSigInt);
642 if (OCProcess() != OC_STACK_OK)
644 OC_LOG(ERROR, TAG, "OCStack process error");
651 OC_LOG(INFO, TAG, "Exiting occlient main loop...");
652 if (OCStop() != OC_STACK_OK)
654 OC_LOG(ERROR, TAG, "OCStack stop error");