ce00796611630960442eaae9bf2bd54b31d846f1
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / occlientbasicops.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
11 //
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.
17 //
18 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <stdint.h>
26 #include <sstream>
27 #include <iostream>
28
29 #include "ocstack.h"
30 #include "logger.h"
31 #include "occlientbasicops.h"
32 #include "ocpayload.h"
33 #include "payload_logging.h"
34 #include "oic_malloc.h"
35 #include "oic_string.h"
36
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)
39
40 static int IPV4_ADDR_SIZE = 24;
41 static int UNICAST_DISCOVERY = 0;
42 static int TEST_CASE = 0;
43 static int CONNECTIVITY = 0;
44
45 static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s/oic/res";
46
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";
51
52 int gQuitFlag = 0;
53
54 struct ResourceNode *resourceList;
55 /*
56  * SIGINT handler: set gQuitFlag to 1 for graceful termination
57  * */
58 void handleSigInt(int signum)
59 {
60     if (signum == SIGINT)
61     {
62         gQuitFlag = 1;
63     }
64 }
65
66 OCPayload* putPayload()
67 {
68     OCRepPayload* payload = OCRepPayloadCreate();
69
70     if(!payload)
71     {
72         std::cout << "Failed to create put payload object"<<std::endl;
73         std::exit(1);
74     }
75
76     OCRepPayloadSetPropInt(payload, "power", 15);
77     OCRepPayloadSetPropBool(payload, "state", true);
78
79     return (OCPayload*) payload;
80 }
81
82 static void PrintUsage()
83 {
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");
93 }
94
95 /*
96  * Returns the first resource in the list
97  */
98 const ResourceNode * getResource()
99 {
100     return resourceList;
101 }
102
103 OCStackResult InvokeOCDoResource(std::ostringstream &query, OCMethod method,
104                                  OCConnectivityType connType, OCQualityOfService qos,
105         OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
106 {
107     OCStackResult ret;
108     OCCallbackData cbData;
109
110     cbData.cb = cb;
111     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
112     cbData.cd = NULL;
113
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);
117
118     if (ret != OC_STACK_OK)
119     {
120         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d",
121                  ret, method);
122     }
123
124     return ret;
125 }
126
127 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle /*handle*/,
128                                 OCClientResponse * clientResponse)
129 {
130     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
131     {
132         OC_LOG(INFO, TAG, "<====Callback Context for PUT received successfully====>");
133     }
134     else
135     {
136         OC_LOG(ERROR, TAG, "<====Callback Context for PUT fail====>");
137     }
138
139     if(clientResponse)
140     {
141         OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
142         OC_LOG(INFO, TAG, PCF("=============> Put Response"));
143     }
144     else
145     {
146         OC_LOG(ERROR, TAG, "<====PUT Callback fail to receive clientResponse====>\n");
147     }
148     return OC_STACK_DELETE_TRANSACTION;
149 }
150
151 OCStackApplicationResult postReqCB(void *ctx, OCDoHandle /*handle*/,
152                           OCClientResponse *clientResponse)
153 {
154     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
155     {
156         OC_LOG(INFO, TAG, "<====Callback Context for POST received successfully====>");
157     }
158     else
159     {
160         OC_LOG(ERROR, TAG, "<====Callback Context for POST fail====>");
161     }
162
163     if(clientResponse)
164     {
165         OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
166         OC_LOG(INFO, TAG, PCF("=============> Post Response"));
167     }
168     else
169     {
170         OC_LOG(ERROR, TAG, "<====POST Callback fail to receive clientResponse====>\n");
171     }
172
173     return OC_STACK_DELETE_TRANSACTION;
174 }
175
176 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle /*handle*/,
177                            OCClientResponse * clientResponse)
178 {
179     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
180     {
181         OC_LOG(INFO, TAG, "<====Callback Context for GET received successfully====>");
182     }
183     else
184     {
185         OC_LOG(ERROR, TAG, "<====Callback Context for GET fail====>");
186     }
187
188     if (clientResponse)
189     {
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"));
194
195         if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0 )
196         {
197             OC_LOG (INFO, TAG, "Received vendor specific options");
198             uint8_t i = 0;
199             OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
200             for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
201             {
202                 if (((OCHeaderOption) rcvdOptions[i]).protocolID == OC_COAP_ID)
203                 {
204                     OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
205                             ((OCHeaderOption)rcvdOptions[i]).optionID );
206
207                     OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
208                         MAX_HEADER_OPTION_DATA_LENGTH);
209                 }
210             }
211         }
212     }
213     else
214     {
215         OC_LOG(ERROR, TAG, "<====GET Callback fail to receive clientResponse====>\n");
216     }
217     return OC_STACK_DELETE_TRANSACTION;
218 }
219
220 /*
221  * This is a function called back when a device is discovered
222  */
223 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle /*handle*/,
224         OCClientResponse * clientResponse)
225 {
226     if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
227     {
228         OC_LOG(INFO, TAG, "\n<====Callback Context for DISCOVERY query "
229                "received successfully====>");
230     }
231     else
232     {
233         OC_LOG(ERROR, TAG, "\n<====Callback Context for DISCOVERY fail====>");
234     }
235
236     if (clientResponse)
237     {
238         OC_LOG_V(INFO, TAG,
239                 "Device =============> Discovered @ %s:%d",
240                 clientResponse->devAddr.addr,
241                 clientResponse->devAddr.port);
242         OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
243
244         collectUniqueResource(clientResponse);
245     }
246     else
247     {
248         OC_LOG(ERROR, TAG, "<====DISCOVERY Callback fail to receive clientResponse====>\n");
249     }
250     return (UNICAST_DISCOVERY) ?
251            OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
252 }
253
254 int InitPutRequest(OCQualityOfService qos)
255 {
256     std::ostringstream query;
257     //Get most recently inserted resource
258     const ResourceNode * resource  = getResource();
259
260     if(!resource)
261     {
262         OC_LOG_V(ERROR, TAG, "Resource null, can't do PUT request\n");
263         return -1;
264     }
265     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
266     OC_LOG_V(INFO, TAG,"Executing InitPutRequest, Query: %s", query.str().c_str());
267
268     return (InvokeOCDoResource(query, OC_REST_PUT, resource->connType,
269            ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
270             putReqCB, NULL, 0));
271 }
272
273 int InitPostRequest(OCQualityOfService qos)
274 {
275     OCStackResult result;
276     std::ostringstream query;
277     //Get most recently inserted resource
278     const ResourceNode * resource  = getResource();
279
280     if(!resource)
281     {
282         OC_LOG_V(ERROR, TAG, "Resource null, can't do POST request\n");
283         return -1;
284     }
285
286     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
287     OC_LOG_V(INFO, TAG,"Executing InitPostRequest, Query: %s", query.str().c_str());
288
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),
292             postReqCB, NULL, 0);
293     if (OC_STACK_OK != result)
294     {
295         // Error can happen if for example, network connectivity is down
296         OC_LOG(ERROR, TAG, "First POST call did not succeed");
297     }
298
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),
302             postReqCB, NULL, 0);
303     if (OC_STACK_OK != result)
304     {
305         OC_LOG(ERROR, TAG, "Second POST call did not succeed");
306     }
307
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));
312 }
313
314 int InitGetRequest(OCQualityOfService qos)
315 {
316     std::ostringstream query;
317     //Get most recently inserted resource
318     const ResourceNode * resource  = getResource();
319
320     if(!resource)
321     {
322         OC_LOG_V(ERROR, TAG, "Resource null, can't do GET request\n");
323         return -1;
324     }
325     query << "coap://" << resource->ip << ":" << resource->port << resource->uri ;
326     OC_LOG_V(INFO, TAG,"Executing InitGetRequest, Query: %s", query.str().c_str());
327
328     return (InvokeOCDoResource(query, OC_REST_GET, resource->connType,
329             (qos == OC_HIGH_QOS)?OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
330 }
331
332 int InitDiscovery()
333 {
334     OCStackResult ret;
335     OCCallbackData cbData;
336     /* Start a discovery query*/
337     char szQueryUri[64] = {};
338     if (UNICAST_DISCOVERY)
339     {
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) ");
343
344         if (fgets(ipv4addr, IPV4_ADDR_SIZE, stdin))
345         {
346             //Strip newline char from ipv4addr
347             StripNewLineChar(ipv4addr);
348             snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DISCOVERY_QUERY, ipv4addr);
349         }
350         else
351         {
352             OC_LOG(ERROR, TAG, "!! Bad input for IPV4 address. !!");
353             return OC_STACK_INVALID_PARAM;
354         }
355     }
356     else
357     {
358         OICStrcpy(szQueryUri, sizeof(szQueryUri), MULTICAST_RESOURCE_DISCOVERY_QUERY);
359     }
360     cbData.cb = discoveryReqCB;
361     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
362     cbData.cd = NULL;
363     if (UNICAST_DISCOVERY)
364     {
365         ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
366                 OC_LOW_QOS, &cbData, NULL, 0);
367     }
368     else
369     {
370         ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, CT_DEFAULT,
371                 OC_LOW_QOS, &cbData, NULL, 0);
372     }
373
374     if (ret != OC_STACK_OK)
375     {
376         OC_LOG(ERROR, TAG, "OCStack resource error");
377     }
378     return ret;
379 }
380
381 const char *getIPAddr(const OCClientResponse *clientResponse)
382 {
383     if (!clientResponse)
384     {
385         return "";
386     }
387
388     const OCDevAddr *devAddr = &clientResponse->devAddr;
389     char *ipaddr = (char *) OICCalloc(1, strlen(devAddr->addr) +1);
390     if (ipaddr)
391     {
392         snprintf(ipaddr, MAX_IP_ADDR_ST_SZ, "%s", devAddr->addr);
393     }
394     else
395     {
396         OC_LOG(ERROR, TAG, "Memory not allocated to ipaddr");
397     }
398     return ipaddr;
399 }
400
401 const char *getPort(const OCClientResponse *clientResponse)
402 {
403     if(!clientResponse)
404     {
405         return "";
406     }
407
408     char *port = NULL;
409     if((port = (char *)OICCalloc(1, MAX_PORT_ST_SZ)))
410     {
411         snprintf(port, MAX_PORT_ST_SZ, "%d", clientResponse->devAddr.port);
412     }
413     else
414     {
415         OC_LOG(ERROR, TAG, "Memory not allocated to port");
416     }
417     return port;
418 }
419
420 void queryResource()
421 {
422     switch(TEST_CASE)
423     {
424         case TEST_DISCOVER_REQ:
425             break;
426         case TEST_NON_CON_OP:
427             InitGetRequest(OC_LOW_QOS);
428             InitPutRequest(OC_LOW_QOS);
429             InitPostRequest(OC_LOW_QOS);
430             break;
431         case TEST_CON_OP:
432             InitGetRequest(OC_HIGH_QOS);
433             InitPutRequest(OC_HIGH_QOS);
434             InitPostRequest(OC_HIGH_QOS);
435             break;
436         default:
437             PrintUsage();
438             break;
439     }
440 }
441
442
443 void collectUniqueResource(const OCClientResponse * clientResponse)
444 {
445     OCResourcePayload* res = ((OCDiscoveryPayload*)clientResponse->payload)->resources;
446     char sidStr[UUID_LENGTH];
447
448     while(res) {
449
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]
456                 );
457
458         if (ret == UUID_LENGTH - 1)
459         {
460             if(insertResource(sidStr, res->uri, clientResponse) == 1)
461             {
462                 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is new");
463                 printResourceList();
464                 queryResource();
465             }
466             else {
467                 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is old");
468             }
469         }
470         else
471         {
472             OC_LOG(ERROR, TAG, "Could Not Retrieve the Server ID");
473         }
474
475         res = res->next;
476     }
477 }
478
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.
482  */
483 int insertResource(const char * sid, char const * uri,
484             const OCClientResponse * clientResponse)
485 {
486     ResourceNode * iter = resourceList;
487     char * sid_cpy =  OICStrdup(sid);
488     char * uri_cpy = OICStrdup(uri);
489
490     //Checking if the resource(sid:uri) is new
491     while(iter)
492     {
493         if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
494         {
495             OICFree(sid_cpy);
496             OICFree(uri_cpy);
497             return 0;
498         }
499         else
500         {
501             iter = iter->next;
502         }
503     }
504
505     //Creating new ResourceNode
506     if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
507     {
508         iter->sid = sid_cpy;
509         iter->uri = uri_cpy;
510         iter->ip = getIPAddr(clientResponse);
511         iter->port = getPort(clientResponse);
512         iter->connType = clientResponse->connType;
513         iter->next = NULL;
514     }
515     else
516     {
517         OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
518         OICFree(sid_cpy);
519         OICFree(uri_cpy);
520         return -1;
521     }
522
523     //Adding new ResourceNode to front of the ResourceList
524     if(!resourceList)
525     {
526         resourceList = iter;
527     }
528     else
529     {
530         iter->next = resourceList;
531         resourceList = iter;
532     }
533     return 1;
534 }
535
536 void printResourceList()
537 {
538     ResourceNode * iter;
539     iter = resourceList;
540     OC_LOG(INFO, TAG, "Resource List: ");
541     while(iter)
542     {
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)
549         {
550             case OC_ADAPTER_IP:
551                 OC_LOG(INFO, TAG, "connType = Default (IPv4)");
552                 break;
553             case OC_ADAPTER_GATT_BTLE:
554                 OC_LOG(INFO, TAG, "connType = BLE");
555                 break;
556             case OC_ADAPTER_RFCOMM_BTEDR:
557                 OC_LOG(INFO, TAG, "connType = BT");
558                 break;
559             default:
560                 OC_LOG(INFO, TAG, "connType = Invalid connType");
561                 break;
562         }
563         OC_LOG(INFO, TAG, "*****************************************************");
564         iter = iter->next;
565     }
566 }
567
568 void freeResourceList()
569 {
570     OC_LOG(INFO, TAG, "Freeing ResourceNode List");
571     ResourceNode * temp;
572     while(resourceList)
573     {
574
575         temp = resourceList;
576         resourceList = resourceList->next;
577         OICFree((void *)temp->sid);
578         OICFree((void *)temp->uri);
579         OICFree((void *)temp->ip);
580         OICFree((void *)temp->port);
581         OICFree(temp);
582     }
583     resourceList = NULL;
584 }
585
586 int main(int argc, char* argv[])
587 {
588     int opt;
589     resourceList = NULL;
590     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
591     {
592         switch(opt)
593         {
594             case 'u':
595                 UNICAST_DISCOVERY = atoi(optarg);
596                 break;
597             case 't':
598                 TEST_CASE = atoi(optarg);
599                 break;
600             case 'c':
601
602                 CONNECTIVITY = atoi(optarg);
603                 break;
604             default:
605                 PrintUsage();
606                 return -1;
607         }
608     }
609
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))
613     {
614         PrintUsage();
615         return -1;
616     }
617
618     /* Initialize OCStack*/
619     if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
620     {
621         OC_LOG(ERROR, TAG, "OCStack init error");
622         return 0;
623     }
624
625     if(CONNECTIVITY == CT_ADAPTER_DEFAULT || CONNECTIVITY ==  CT_IP)
626     {
627         OC_CONNTYPE =  CT_ADAPTER_IP;//CT_DEFAULT;
628     }
629     else
630     {
631         OC_LOG(INFO, TAG, "Default Connectivity type selected");
632         PrintUsage();
633     }
634
635     InitDiscovery();
636
637     // Break from loop with Ctrl+C
638     signal(SIGINT, handleSigInt);
639
640     while (!gQuitFlag)
641     {
642         if (OCProcess() != OC_STACK_OK)
643         {
644             OC_LOG(ERROR, TAG, "OCStack process error");
645             return 0;
646         }
647         sleep(2);
648     }
649
650     freeResourceList();
651     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
652     if (OCStop() != OC_STACK_OK)
653     {
654         OC_LOG(ERROR, TAG, "OCStack stop error");
655     }
656     return 0;
657 }
658
659