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