4a374df4b736fce6fc8483ad80ca91231ef21ab3
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / linux / SimpleClientServer / occlientslow.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 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <iostream>
27 #include <sstream>
28 #include "ocstack.h"
29 #include "logger.h"
30 #include "occlientslow.h"
31
32 static int UNICAST_DISCOVERY = 0;
33 static int TEST_CASE = 0;
34 static const char * TEST_APP_UNICAST_DISCOVERY_QUERY = "coap://0.0.0.0:5683/oc/core";
35 static std::string putPayload = "{\"state\":\"off\",\"power\":10}";
36 static std::string coapServerIP = "255.255.255.255";
37 static std::string coapServerPort = "5683";
38 static std::string coapServerResource = "/a/led";
39
40 int gQuitFlag = 0;
41
42 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
43 void handleSigInt(int signum)
44 {
45     if (signum == SIGINT)
46     {
47         gQuitFlag = 1;
48     }
49 }
50
51 static void PrintUsage()
52 {
53     OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3>");
54     OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
55     OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
56     OC_LOG(INFO, TAG, "-t 2 : Discover Resources and Initiate Nonconfirmable Get Request");
57     OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate Confirmable Get Request");
58 }
59
60 OCStackResult InvokeOCDoResource(std::ostringstream &query,
61         OCMethod method, OCQualityOfService qos,
62         OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
63 {
64     OCStackResult ret;
65     OCCallbackData cbData;
66     OCDoHandle handle;
67
68     cbData.cb = cb;
69     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
70     cbData.cd = NULL;
71
72 #ifdef CA_INT
73     // TODO-CA: The adapter type is set to WiFi but should be configurable - add as API param
74     ret = OCDoResource(&handle, method, query.str().c_str(), 0,
75             NULL, OC_WIFI, qos, &cbData, options, numOptions);
76 #else
77     ret = OCDoResource(&handle, method, query.str().c_str(), 0,
78             NULL, qos, &cbData, options, numOptions);
79 #endif
80
81     if (ret != OC_STACK_OK)
82     {
83         OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
84     }
85
86     return ret;
87 }
88
89 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
90 {
91     if(clientResponse == NULL)
92     {
93         OC_LOG(INFO, TAG, "The clientResponse is NULL");
94         return   OC_STACK_DELETE_TRANSACTION;
95     }
96     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
97     {
98         OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
99     }
100
101     OC_LOG_V(INFO, TAG, "StackResult: %s",  getResult(clientResponse->result));
102     OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
103     OC_LOG_V(INFO, TAG, "JSON = %s =============> Get Response",
104             clientResponse->resJSONPayload);
105
106     if(clientResponse->rcvdVendorSpecificHeaderOptions &&
107             clientResponse->numRcvdVendorSpecificHeaderOptions)
108     {
109         OC_LOG (INFO, TAG, "Received vendor specific options");
110         uint8_t i = 0;
111         OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
112         for( i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
113         {
114             if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
115             {
116                 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
117                         ((OCHeaderOption)rcvdOptions[i]).optionID );
118                 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
119                         ((OCHeaderOption)rcvdOptions[i]).optionLength);
120             }
121         }
122     }
123     return OC_STACK_DELETE_TRANSACTION;
124 }
125
126 // This is a function called back when a device is discovered
127 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
128         OCClientResponse * clientResponse)
129 {
130     uint8_t remoteIpAddr[4];
131     uint16_t remotePortNu;
132
133     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
134     {
135         OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
136     }
137
138     if (clientResponse)
139     {
140         OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
141
142         OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
143                 remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
144         OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
145
146         OC_LOG_V(INFO, TAG,
147                 "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
148                 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
149                 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
150
151         parseClientResponse(clientResponse);
152
153         switch(TEST_CASE)
154         {
155             case TEST_NON_CON_OP:
156                 InitGetRequest(OC_LOW_QOS);
157                 break;
158             case TEST_CON_OP:
159                 InitGetRequest(OC_HIGH_QOS);
160                 break;
161             default:
162                 PrintUsage();
163                 break;
164         }
165     }
166
167     return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
168
169 }
170
171 int InitGetRequest(OCQualityOfService qos)
172 {
173     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
174     std::ostringstream query;
175     query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
176
177     return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)?
178             OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
179 }
180
181 int InitDiscovery()
182 {
183     OCStackResult ret;
184     OCCallbackData cbData;
185     OCDoHandle handle;
186     /* Start a discovery query*/
187     char szQueryUri[64] = { 0 };
188     if (UNICAST_DISCOVERY)
189     {
190         strcpy(szQueryUri, TEST_APP_UNICAST_DISCOVERY_QUERY);
191     }
192     else
193     {
194         strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
195     }
196     cbData.cb = discoveryReqCB;
197     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
198     cbData.cd = NULL;
199 #ifdef CA_INT
200     // TODO-CA: The adapter type is set to all but should be configurable - add as API param
201     ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, (OC_ETHERNET | OC_WIFI | OC_LE),
202                         OC_LOW_QOS, &cbData, NULL, 0);
203 #else
204     ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_LOW_QOS, &cbData, NULL, 0);
205 #endif
206     if (ret != OC_STACK_OK)
207     {
208         OC_LOG(ERROR, TAG, "OCStack resource error");
209     }
210     return ret;
211 }
212
213 int main(int argc, char* argv[])
214 {
215     uint8_t addr[20] = {0};
216     uint8_t* paddr = NULL;
217     uint16_t port = USE_RANDOM_PORT;
218     uint8_t ifname[] = "eth0";
219     int opt;
220
221     while ((opt = getopt(argc, argv, "u:t:")) != -1)
222     {
223         switch(opt)
224         {
225             case 'u':
226                 UNICAST_DISCOVERY = atoi(optarg);
227                 break;
228             case 't':
229                 TEST_CASE = atoi(optarg);
230                 break;
231             default:
232                 PrintUsage();
233                 return -1;
234         }
235     }
236
237     if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
238             (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
239     {
240         PrintUsage();
241         return -1;
242     }
243
244
245     /*Get Ip address on defined interface and initialize coap on it with random port number
246      * this port number will be used as a source port in all coap communications*/
247     if ( OCGetInterfaceAddress(ifname, sizeof(ifname), AF_INET, addr,
248                 sizeof(addr)) == ERR_SUCCESS)
249     {
250         OC_LOG_V(INFO, TAG, "Starting occlient on address %s",addr);
251         paddr = addr;
252     }
253
254     /* Initialize OCStack*/
255     if (OCInit((char *) paddr, port, OC_CLIENT) != OC_STACK_OK)
256     {
257         OC_LOG(ERROR, TAG, "OCStack init error");
258         return 0;
259     }
260
261     InitDiscovery();
262
263     // Break from loop with Ctrl+C
264     OC_LOG(INFO, TAG, "Entering occlient main loop...");
265     signal(SIGINT, handleSigInt);
266     while (!gQuitFlag)
267     {
268         if (OCProcess() != OC_STACK_OK)
269         {
270             OC_LOG(ERROR, TAG, "OCStack process error");
271             return 0;
272         }
273
274         sleep(2);
275     }
276     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
277
278     if (OCStop() != OC_STACK_OK)
279     {
280         OC_LOG(ERROR, TAG, "OCStack stop error");
281     }
282
283     return 0;
284 }
285
286 std::string getIPAddrTBServer(OCClientResponse * clientResponse)
287 {
288     if(!clientResponse) return "";
289     if(!clientResponse->addr) return "";
290     uint8_t a, b, c, d = 0;
291     if(0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d) ) return "";
292
293     char ipaddr[16] = {'\0'};
294     // ostringstream not working correctly here, hence snprintf
295     snprintf(ipaddr,  sizeof(ipaddr), "%d.%d.%d.%d", a,b,c,d);
296     return std::string (ipaddr);
297 }
298
299
300 std::string getPortTBServer(OCClientResponse * clientResponse)
301 {
302     if(!clientResponse) return "";
303     if(!clientResponse->addr) return "";
304     uint16_t p = 0;
305     if(0 != OCDevAddrToPort(clientResponse->addr, &p) ) return "";
306     std::ostringstream ss;
307     ss << p;
308     return ss.str();
309 }
310
311 std::string getQueryStrForGetPut(OCClientResponse * clientResponse)
312 {
313     return "/a/led";
314 }
315
316 void parseClientResponse(OCClientResponse * clientResponse)
317 {
318     coapServerIP = getIPAddrTBServer(clientResponse);
319     coapServerPort = getPortTBServer(clientResponse);
320     coapServerResource = getQueryStrForGetPut(clientResponse);
321 }