Imported Upstream version 1.0.1
[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 UnicastDiscovery = 0;
41 static int TestCase = 0;
42 static int Connectivity = 0;
43
44 //The following variable determines the interface protocol (IP, etc)
45 //to be used for sending unicast messages. Default set to IP.
46 static OCConnectivityType ConnType = CT_ADAPTER_IP;
47 static const char *RESOURCE_DISCOVERY_QUERY = "%s/oic/res";
48
49 int gQuitFlag = 0;
50
51 struct ResourceNode *resourceList;
52 /*
53  * SIGINT handler: set gQuitFlag to 1 for graceful termination
54  * */
55 void handleSigInt(int signum)
56 {
57     if (signum == SIGINT)
58     {
59         gQuitFlag = 1;
60     }
61 }
62
63 OCPayload* putPayload()
64 {
65     OCRepPayload* payload = OCRepPayloadCreate();
66
67     if(!payload)
68     {
69         std::cout << "Failed to create put payload object"<<std::endl;
70         std::exit(1);
71     }
72
73     OCRepPayloadSetPropInt(payload, "power", 15);
74     OCRepPayloadSetPropBool(payload, "state", true);
75
76     return (OCPayload*) payload;
77 }
78
79 static void PrintUsage()
80 {
81     OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3> -c <0|1>");
82     OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
83     OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
84     OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
85             " Initiate Nonconfirmable Get/Put/Post Requests");
86     OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate "
87             "Confirmable Get/Put/Post Requests");
88     OC_LOG(INFO, TAG, "-c 0 : Default auto-selection");
89     OC_LOG(INFO, TAG, "-c 1 : IP Connectivity Type");
90 }
91
92 /*
93  * Returns the first resource in the list
94  */
95 const ResourceNode * getResource()
96 {
97     return resourceList;
98 }
99
100 OCStackResult InvokeOCDoResource(std::ostringstream &query,
101                                  OCMethod method,
102                                  const OCDevAddr *dest,
103                                  OCQualityOfService qos,
104                                  OCClientResponseHandler cb,
105                                  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(), dest,
115         (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload() : NULL,
116          CT_DEFAULT, 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, clientResponse->payload);
142         OC_LOG(INFO, TAG, ("=============> 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, clientResponse->payload);
166         OC_LOG(INFO, TAG, ("=============> 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, clientResponse->payload);
193         OC_LOG(INFO, TAG, ("=============> 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, 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 (UnicastDiscovery) ?
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 << 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->endpoint,
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 << 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->endpoint,
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->endpoint,
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->endpoint,
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 << 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->endpoint,
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     char queryUri[200];
337     char ipaddr[100] = { '\0' };
338
339     if (UnicastDiscovery)
340     {
341         OC_LOG(INFO, TAG, "Enter IP address (with optional port) of the Server hosting resource\n");
342         OC_LOG(INFO, TAG, "IPv4: 192.168.0.15:45454\n");
343         OC_LOG(INFO, TAG, "IPv6: [fe80::20c:29ff:fe1b:9c5]:45454\n");
344
345         if (fgets(ipaddr, sizeof (ipaddr), stdin))
346         {
347             StripNewLineChar(ipaddr); //Strip newline char from ipaddr
348         }
349         else
350         {
351             OC_LOG(ERROR, TAG, "!! Bad input for IP address. !!");
352             return OC_STACK_INVALID_PARAM;
353         }
354     }
355
356     snprintf(queryUri, sizeof (queryUri), RESOURCE_DISCOVERY_QUERY, ipaddr);
357
358     cbData.cb = discoveryReqCB;
359     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
360     cbData.cd = NULL;
361
362     ret = OCDoResource(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,
363                        OC_LOW_QOS, &cbData, NULL, 0);
364     if (ret != OC_STACK_OK)
365     {
366         OC_LOG(ERROR, TAG, "OCStack resource error");
367     }
368     return ret;
369 }
370
371 void queryResource()
372 {
373     switch(TestCase)
374     {
375         case TEST_DISCOVER_REQ:
376             break;
377         case TEST_NON_CON_OP:
378             InitGetRequest(OC_LOW_QOS);
379             InitPutRequest(OC_LOW_QOS);
380             InitPostRequest(OC_LOW_QOS);
381             break;
382         case TEST_CON_OP:
383             InitGetRequest(OC_HIGH_QOS);
384             InitPutRequest(OC_HIGH_QOS);
385             InitPostRequest(OC_HIGH_QOS);
386             break;
387         default:
388             PrintUsage();
389             break;
390     }
391 }
392
393
394 void collectUniqueResource(const OCClientResponse * clientResponse)
395 {
396     OCDiscoveryPayload* pay = (OCDiscoveryPayload*) clientResponse->payload;
397     OCResourcePayload* res = pay->resources;
398
399     // Including the NUL terminator, length of UUID string of the form:
400     //   "a62389f7-afde-00b6-cd3e-12b97d2fcf09"
401 #   define UUID_LENGTH 37
402
403     char sidStr[UUID_LENGTH];
404
405     while(res) {
406
407         int ret = snprintf(sidStr, UUID_LENGTH,
408                 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
409                 pay->sid[0], pay->sid[1], pay->sid[2], pay->sid[3],
410                 pay->sid[4], pay->sid[5], pay->sid[6], pay->sid[7],
411                 pay->sid[8], pay->sid[9], pay->sid[10], pay->sid[11],
412                 pay->sid[12], pay->sid[13], pay->sid[14], pay->sid[15]
413                 );
414
415         if (ret == UUID_LENGTH - 1)
416         {
417             if(insertResource(sidStr, res->uri, clientResponse) == 1)
418             {
419                 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is new");
420                 printResourceList();
421                 queryResource();
422             }
423             else {
424                 OC_LOG_V(INFO,TAG,"%s%s%s%s\n",sidStr, ":", res->uri, " is old");
425             }
426         }
427         else
428         {
429             OC_LOG(ERROR, TAG, "Could Not Retrieve the Server ID");
430         }
431
432         res = res->next;
433     }
434 }
435
436 /* This function searches for the resource(sid:uri) in the ResourceList.
437  * If the Resource is found in the list then it returns 0 else insert
438  * the resource to front of the list and returns 1.
439  */
440 int insertResource(const char * sid, char const * uri,
441             const OCClientResponse * clientResponse)
442 {
443     ResourceNode * iter = resourceList;
444     char * sid_cpy =  OICStrdup(sid);
445     char * uri_cpy = OICStrdup(uri);
446
447     //Checking if the resource(sid:uri) is new
448     while(iter)
449     {
450         if((strcmp(iter->sid, sid) == 0) && (strcmp(iter->uri, uri) == 0))
451         {
452             OICFree(sid_cpy);
453             OICFree(uri_cpy);
454             return 0;
455         }
456         else
457         {
458             iter = iter->next;
459         }
460     }
461
462     //Creating new ResourceNode
463     if((iter = (ResourceNode *) OICMalloc(sizeof(ResourceNode))))
464     {
465         iter->sid = sid_cpy;
466         iter->uri = uri_cpy;
467         iter->endpoint = clientResponse->devAddr;
468         iter->next = NULL;
469     }
470     else
471     {
472         OC_LOG(ERROR, TAG, "Memory not allocated to ResourceNode");
473         OICFree(sid_cpy);
474         OICFree(uri_cpy);
475         return -1;
476     }
477
478     //Adding new ResourceNode to front of the ResourceList
479     if(!resourceList)
480     {
481         resourceList = iter;
482     }
483     else
484     {
485         iter->next = resourceList;
486         resourceList = iter;
487     }
488     return 1;
489 }
490
491 void printResourceList()
492 {
493     ResourceNode * iter;
494     iter = resourceList;
495     OC_LOG(INFO, TAG, "Resource List: ");
496     while(iter)
497     {
498         OC_LOG(INFO, TAG, "*****************************************************");
499         OC_LOG_V(INFO, TAG, "sid = %s",iter->sid);
500         OC_LOG_V(INFO, TAG, "uri = %s", iter->uri);
501         OC_LOG_V(INFO, TAG, "ip = %s", iter->endpoint.addr);
502         OC_LOG_V(INFO, TAG, "port = %d", iter->endpoint.port);
503         switch (iter->endpoint.adapter)
504         {
505             case OC_ADAPTER_IP:
506                 OC_LOG(INFO, TAG, "connType = Default (IPv4)");
507                 break;
508             case OC_ADAPTER_GATT_BTLE:
509                 OC_LOG(INFO, TAG, "connType = BLE");
510                 break;
511             case OC_ADAPTER_RFCOMM_BTEDR:
512                 OC_LOG(INFO, TAG, "connType = BT");
513                 break;
514             default:
515                 OC_LOG(INFO, TAG, "connType = Invalid connType");
516                 break;
517         }
518         OC_LOG(INFO, TAG, "*****************************************************");
519         iter = iter->next;
520     }
521 }
522
523 void freeResourceList()
524 {
525     OC_LOG(INFO, TAG, "Freeing ResourceNode List");
526     ResourceNode * temp;
527     while(resourceList)
528     {
529
530         temp = resourceList;
531         resourceList = resourceList->next;
532         OICFree((void *)temp->sid);
533         OICFree((void *)temp->uri);
534         OICFree(temp);
535     }
536     resourceList = NULL;
537 }
538
539 int main(int argc, char* argv[])
540 {
541     int opt;
542     resourceList = NULL;
543     while ((opt = getopt(argc, argv, "u:t:c:")) != -1)
544     {
545         switch(opt)
546         {
547             case 'u':
548                 UnicastDiscovery = atoi(optarg);
549                 break;
550             case 't':
551                 TestCase = atoi(optarg);
552                 break;
553             case 'c':
554                 Connectivity = atoi(optarg);
555                 break;
556             default:
557                 PrintUsage();
558                 return -1;
559         }
560     }
561
562     if ((UnicastDiscovery != 0 && UnicastDiscovery != 1) ||
563         (TestCase < TEST_DISCOVER_REQ || TestCase >= MAX_TESTS) ||
564         (Connectivity < CT_ADAPTER_DEFAULT || Connectivity >= MAX_CT))
565     {
566         PrintUsage();
567         return -1;
568     }
569
570     /* Initialize OCStack*/
571     if (OCInit1(OC_CLIENT, OC_DEFAULT_FLAGS, OC_DEFAULT_FLAGS) != OC_STACK_OK)
572     {
573         OC_LOG(ERROR, TAG, "OCStack init error");
574         return 0;
575     }
576
577     if(Connectivity == CT_ADAPTER_DEFAULT || Connectivity ==  CT_IP)
578     {
579         ConnType =  CT_ADAPTER_IP;//CT_DEFAULT;
580     }
581     else
582     {
583         OC_LOG(INFO, TAG, "Default Connectivity type selected");
584         PrintUsage();
585     }
586
587     InitDiscovery();
588
589     // Break from loop with Ctrl+C
590     signal(SIGINT, handleSigInt);
591
592     while (!gQuitFlag)
593     {
594         if (OCProcess() != OC_STACK_OK)
595         {
596             OC_LOG(ERROR, TAG, "OCStack process error");
597             return 0;
598         }
599         sleep(2);
600     }
601
602     freeResourceList();
603     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
604     if (OCStop() != OC_STACK_OK)
605     {
606         OC_LOG(ERROR, TAG, "OCStack stop error");
607     }
608     return 0;
609 }
610
611