To come on this changeset: All convergences between and server and client observation...
[platform/upstream/iotivity.git] / csdk / stack / samples / SimpleClientServer / occlient.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation 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 <ocstack.h>
27 #include <iostream>
28 #include <sstream>
29
30 char *getResult(OCStackResult result);
31 std::string getIPAddrTBServer(OCClientResponse * clientResponse);
32 std::string getPortTBServer(OCClientResponse * clientResponse);
33 std::string getQueryStrForGetPut(unsigned  const char * responsePayload);
34
35 #define TAG PCF("occlient")
36 #define CTX_VAL 0x99
37 #ifndef MAX_LENGTH_IPv4_ADDR
38 #define MAX_LENGTH_IPv4_ADDR 16
39 #endif
40
41 #define MAX_TEST_CASES 5
42
43 static int UNICAST_DISCOVERY = 0;
44 static int TEST_CASE = 0;
45 static std::string putPayload = "{\"state\":\"off\",\"power\":\"0\"}";
46
47 // The handle for the observe registration
48 OCDoHandle gObserveDoHandle;
49 // After this crosses a threshold client deregisters for further observations
50 int gNumNotifies = 1;
51
52 int gQuitFlag = 0;
53 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
54 void handleSigInt(int signum) {
55         if (signum == SIGINT) {
56                 gQuitFlag = 1;
57         }
58 }
59
60 // Forward Declaration
61 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse);
62 int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse);
63 int InitObserveRequest(OCClientResponse * clientResponse);
64 int InitPutRequest(OCClientResponse * clientResponse);
65 int InitGetRequest(OCClientResponse * clientResponse);
66 int InitDiscovery();
67
68 void PrintUsage()
69 {
70     OC_LOG(INFO, TAG, "Usage : occlient <Unicast Discovery> <Test Case>");
71     OC_LOG(INFO, TAG, "Test Case 1 : Discover Resources");
72     OC_LOG(INFO, TAG, "Test Case 2 : Discover Resources and Initiate Get Request");
73     OC_LOG(INFO, TAG, "Test Case 3 : Discover Resources and Initiate Get/Put Requests");
74     OC_LOG(INFO, TAG, "Test Case 4 : Discover Resources and Initiate Observe Requests");
75     OC_LOG(INFO, TAG, "Test Case 5 : Discover Resources and Initiate Get Request for a resource which is unavailable");
76 }
77
78 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
79         if(clientResponse) {}
80         if(ctx == (void*)CTX_VAL) {
81                 OC_LOG_V(INFO, TAG, "Callback Context for PUT query recvd successfully");
82                 OC_LOG_V(INFO, TAG, "JSON = %s =============> Discovered", clientResponse->resJSONPayload);
83         }
84
85         return OC_STACK_KEEP_TRANSACTION;
86 }
87
88 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse) {
89     OC_LOG_V(INFO, TAG, "StackResult: %s",
90             getResult(clientResponse->result));
91     if(ctx == (void*)CTX_VAL) {
92         OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
93         if(clientResponse->sequenceNumber == 0) {
94             OC_LOG_V(INFO, TAG, "Callback Context for GET query recvd successfully");
95             OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
96         }
97         else {
98             OC_LOG_V(INFO, TAG, "Callback Context for OBSERVE notification recvd successfully %d", gNumNotifies);
99             OC_LOG_V(INFO, TAG, "Fnd' Rsrc': %s", clientResponse->resJSONPayload);
100             gNumNotifies++;
101             if (gNumNotifies == 3)
102             {
103                 if (OCCancel (gObserveDoHandle) != OC_STACK_OK){
104                     OC_LOG(ERROR, TAG, "Observe cancel error");
105                 }
106             }
107         }
108         }
109         return OC_STACK_KEEP_TRANSACTION;
110 }
111
112
113 // This is a function called back when a device is discovered
114 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
115         OCClientResponse * clientResponse) {
116     uint8_t remoteIpAddr[4];
117     uint16_t remotePortNu;
118
119     OC_LOG(INFO, TAG,
120             "Entering discoveryReqCB (Application Layer CB)");
121     OC_LOG_V(INFO, TAG, "StackResult: %s",
122             getResult(clientResponse->result));
123
124     if (ctx == (void*) CTX_VAL) {
125         OC_LOG_V(INFO, TAG, "Callback Context recvd successfully");
126     }
127
128     OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
129             remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
130     OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
131
132     OC_LOG_V(INFO, TAG,
133             "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
134             clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
135             remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
136
137     if (TEST_CASE == 2)
138     {
139         InitGetRequest(clientResponse);
140     }
141     else if (TEST_CASE == 3)
142     {
143         InitPutRequest(clientResponse);
144     }
145     else if (TEST_CASE == 4)
146     {
147         InitObserveRequest(clientResponse);
148     }
149     else if (TEST_CASE == 5)
150     {
151         InitGetRequestToUnavailableResource(clientResponse);
152     }
153         return OC_STACK_KEEP_TRANSACTION;
154 }
155
156
157 int InitGetRequestToUnavailableResource(OCClientResponse * clientResponse)
158 {
159     OCStackResult ret;
160         OCCallbackData cbData;
161     OCDoHandle handle;
162     std::ostringstream getQuery;
163     getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << "/SomeUnknownResource";
164     cbData.cb = getReqCB;
165     cbData.context = (void*)CTX_VAL;
166     ret = OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
167     if (ret != OC_STACK_OK)
168     {
169                 OC_LOG(ERROR, TAG, "OCStack resource error");
170     }
171     return ret;
172 }
173
174
175 int InitObserveRequest(OCClientResponse * clientResponse)
176 {
177     OCStackResult ret;
178     OCCallbackData cbData;
179     OCDoHandle handle;
180     std::ostringstream obsReg;
181     obsReg << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
182     cbData.cb = getReqCB;
183     cbData.context = (void*)CTX_VAL;
184     OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
185     ret = OCDoResource(&handle, OC_REST_OBSERVE, obsReg.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
186     if (ret != OC_STACK_OK)
187     {
188         OC_LOG(ERROR, TAG, "OCStack resource error");
189     }
190     else 
191     {
192         gObserveDoHandle = handle;
193     }
194     return ret;
195 }
196
197
198 int InitPutRequest(OCClientResponse * clientResponse)
199 {
200     OCStackResult ret;
201     OCCallbackData cbData;
202     OCDoHandle handle;
203     //* Make a PUT query*/
204     std::ostringstream getQuery;
205     getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
206     cbData.cb = putReqCB;
207     cbData.context = (void*)CTX_VAL;
208     OC_LOG_V(INFO, TAG, "PUT payload from client = %s ", putPayload.c_str());
209     ret = OCDoResource(&handle, OC_REST_PUT, getQuery.str().c_str(), 0, putPayload.c_str(), OC_NON_CONFIRMABLE, &cbData);
210     if (ret != OC_STACK_OK)
211     {
212         OC_LOG(ERROR, TAG, "OCStack resource error");
213     }
214     return ret;
215 }
216
217
218 int InitGetRequest(OCClientResponse * clientResponse)
219 {
220     OCStackResult ret;
221         OCCallbackData cbData;
222     OCDoHandle handle;
223     //* Make a GET query*/
224     std::ostringstream getQuery;
225     getQuery << "coap://" << getIPAddrTBServer(clientResponse) << ":" << getPortTBServer(clientResponse) << getQueryStrForGetPut(clientResponse->resJSONPayload);
226     cbData.cb = getReqCB;
227     cbData.context = (void*)CTX_VAL;
228     ret = OCDoResource(&handle, OC_REST_GET, getQuery.str().c_str(), 0, 0, OC_NON_CONFIRMABLE, &cbData);
229     if (ret != OC_STACK_OK)
230     {
231                 OC_LOG(ERROR, TAG, "OCStack resource error");
232     }
233     return ret;
234 }
235
236 #define TEST_APP_UNICAST_DISCOVERY_QUERY                  PCF("coap://0.0.0.0:5683/oc/core")
237 int InitDiscovery()
238 {
239     OCStackResult ret;
240         OCCallbackData cbData;
241     OCDoHandle handle;
242         /* Start a discovery query*/
243         char szQueryUri[64] = { 0 };
244     if (UNICAST_DISCOVERY)
245     {
246         strcpy(szQueryUri, TEST_APP_UNICAST_DISCOVERY_QUERY);
247     }
248     else
249     {
250         strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
251     }
252         cbData.cb = discoveryReqCB;
253         cbData.context = (void*)CTX_VAL;
254         ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_NON_CONFIRMABLE, &cbData);
255     if (ret != OC_STACK_OK)
256     {
257                 OC_LOG(ERROR, TAG, "OCStack resource error");
258     }
259     return ret;
260 }
261
262 int main(int argc, char* argv[]) {
263         uint8_t addr[20] = {0};
264         uint8_t* paddr = NULL;
265         uint16_t port = USE_RANDOM_PORT;
266         uint8_t ifname[] = "eth0";
267
268     if (argc == 3)
269     {
270         UNICAST_DISCOVERY = atoi(argv[1]);
271         TEST_CASE = atoi(argv[2]);
272         if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
273             (TEST_CASE < 1 || TEST_CASE > MAX_TEST_CASES) )
274         {
275             PrintUsage();
276             return -1;
277         }
278     }
279     else
280     {
281         PrintUsage();
282         return -1;
283     }
284
285
286         /*Get Ip address on defined interface and initialize coap on it with random port number
287          * this port number will be used as a source port in all coap communications*/
288     if ( OCGetInterfaceAddress(ifname, sizeof(ifname), AF_INET, addr,
289                                sizeof(addr)) == ERR_SUCCESS)
290     {
291         OC_LOG_V(INFO, TAG, "Starting occlient on address %s",addr);
292         paddr = addr;
293     }
294
295         /* Initialize OCStack*/
296         if (OCInit((char *) paddr, port, OC_CLIENT) != OC_STACK_OK) {
297                 OC_LOG(ERROR, TAG, "OCStack init error");
298                 return 0;
299         }
300
301     InitDiscovery();
302
303         // Break from loop with Ctrl+C
304         OC_LOG(INFO, TAG, "Entering occlient main loop...");
305         signal(SIGINT, handleSigInt);
306         while (!gQuitFlag) {
307
308                 if (OCProcess() != OC_STACK_OK) {
309                         OC_LOG(ERROR, TAG, "OCStack process error");
310                         return 0;
311                 }
312
313                 sleep(3);
314         }
315         OC_LOG(INFO, TAG, "Exiting occlient main loop...");
316
317         if (OCStop() != OC_STACK_OK) {
318                 OC_LOG(ERROR, TAG, "OCStack stop error");
319         }
320
321         return 0;
322 }
323
324 char *getResult(OCStackResult result) {
325         char *resString = new char[40];
326         memset(resString, 0, 40);
327     strcpy(resString, "Result: ");
328     switch (result) {
329     case OC_STACK_OK:
330         strcat(resString, "OC_STACK_OK");
331         break;
332     case OC_STACK_INVALID_URI:
333         strcat(resString, "OC_STACK_INVALID_URI");
334         break;
335     case OC_STACK_INVALID_QUERY:
336         strcat(resString, "OC_STACK_INVALID_QUERY");
337         break;
338     case OC_STACK_INVALID_IP:
339         strcat(resString, "OC_STACK_INVALID_IP");
340         break;
341     case OC_STACK_INVALID_PORT:
342         strcat(resString, "OC_STACK_INVALID_PORT");
343         break;
344     case OC_STACK_INVALID_CALLBACK:
345         strcat(resString, "OC_STACK_INVALID_CALLBACK");
346         break;
347     case OC_STACK_INVALID_METHOD:
348         strcat(resString, "OC_STACK_INVALID_METHOD");
349         break;
350     case OC_STACK_NO_MEMORY:
351         strcat(resString, "OC_STACK_NO_MEMORY");
352         break;
353     case OC_STACK_COMM_ERROR:
354         strcat(resString, "OC_STACK_COMM_ERROR");
355         break;
356     case OC_STACK_INVALID_PARAM:
357         strcat(resString, "OC_STACK_INVALID_PARAM");
358         break;
359     case OC_STACK_NOTIMPL:
360         strcat(resString, "OC_STACK_NOTIMPL");
361         break;
362     case OC_STACK_NO_RESOURCE:
363         strcat(resString, "OC_STACK_NO_RESOURCE");
364         break;
365     case OC_STACK_RESOURCE_ERROR:
366         strcat(resString, "OC_STACK_RESOURCE_ERROR");
367         break;
368     case OC_STACK_SLOW_RESOURCE:
369         strcat(resString, "OC_STACK_SLOW_RESOURCE");
370         break;
371     case OC_STACK_ERROR:
372         strcat(resString, "OC_STACK_ERROR");
373         break;
374     default:
375         strcat(resString, "UNKNOWN");
376     }
377     return resString;
378 }
379
380
381 std::string getIPAddrTBServer(OCClientResponse * clientResponse) {
382         if(!clientResponse) return "";
383         if(!clientResponse->addr) return "";
384         uint8_t a, b, c, d = 0;
385         if(0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d) ) return "";
386
387         char ipaddr[16] = {'\0'};
388         snprintf(ipaddr,  sizeof(ipaddr), "%d.%d.%d.%d", a,b,c,d); // ostringstream not working correctly here, hence snprintf
389         //printf("IP address string of the TB server = %s\n", *out_ipaddr);
390         return std::string (ipaddr);
391 }
392
393
394 std::string getPortTBServer(OCClientResponse * clientResponse){
395         if(!clientResponse) return "";
396         if(!clientResponse->addr) return "";
397         uint16_t p = 0;
398         if(0 != OCDevAddrToPort(clientResponse->addr, &p) ) return "";
399         std::ostringstream ss;
400         ss << p;
401         return ss.str();
402 }
403
404 std::string getQueryStrForGetPut(unsigned  const char * responsePayload){
405         //  JSON = {"oc":{"payload":[{"href":"/a/led","rt":["core.led"],"if":["core.rw"],"obs":1}]}}
406
407         //std::string jsonPayload(responsePayload, responsePayload + sizeof responsePayload / sizeof responsePayload[0]);
408         std::string jsonPayload(reinterpret_cast<char*>(const_cast<unsigned char*>(responsePayload)));
409         //std::cout << jsonPayload << std::endl;
410
411         return "/a/led";
412 }