examples: Add notice about using experimental API
[iotivity.git] / service / coap-http-proxy / samples / proxy_client.c
1 //******************************************************************
2 //
3 // Copyright 2016 Samsung Electronics 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 "iotivity_config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <signal.h>
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include <getopt.h>
32
33 #include "ocstack.h"
34 #include "ocpayload.h"
35
36 /// This example is using experimental API, so there is no guarantee of support for future release,
37 /// nor any there any guarantee that breaking changes will not occur across releases.
38 #include "experimental/logger.h"
39 #include "experimental/payload_logging.h"
40
41 /**
42  * List of methods that can be initiated from proxy client
43  */
44 typedef enum {
45     TEST_DISCOVER_REQ = 1,
46     TEST_GET_REQ,
47     TEST_POST_REQ,
48     TEST_PUT_REQ,
49     TEST_DELETE_REQ,
50     MAX_TESTS
51 } clientTests_t;
52
53 #define TAG "PROXY_CLIENT"
54 #define MAX_HTTP_URI_LENGTH 1024
55 // Tracking user input
56 static clientTests_t testCase = MAX_TESTS;
57 static const char* discoveryQuery = "/oic/res";
58 static OCDevAddr serverAddr;
59 OCConnectivityType connType;
60
61 // Will be taken as user input
62 static char httpResource[MAX_HTTP_URI_LENGTH];
63
64 static char CRED_FILE_DEVOWNER[] = "oic_svr_db_client_devowner.dat";
65
66 int gQuitFlag = 0;
67 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
68 void handleSigInt(int signum)
69 {
70     if (signum == SIGINT)
71     {
72         gQuitFlag = 1;
73     }
74 }
75
76 OCPayload* putPayload()
77 {
78     OCRepPayload* payload = OCRepPayloadCreate();
79     if (!payload)
80     {
81         OIC_LOG(INFO, TAG, "Failed to create payload object");
82         return NULL;
83     }
84
85     /* Set properties for your http server here.
86     */
87     OCRepPayloadSetPropInt(payload, "power", 10);
88     OCRepPayloadSetPropBool(payload, "state", true);
89
90     return (OCPayload*)payload;
91 }
92
93 static void PrintUsage()
94 {
95     OIC_LOG(INFO, TAG, "Usage : proxy_client -t <1..5>");
96     OIC_LOG(INFO, TAG, "-t 1  :  Discover Proxy");
97     OIC_LOG(INFO, TAG, "-t 2 -p \"http_uri\":  Discover Proxy and Initiate HTTP GET Request");
98     OIC_LOG(INFO, TAG, "-t 3 -p \"http_uri\":  Discover Proxy and Initiate HTTP POST Request");
99     OIC_LOG(INFO, TAG, "-t 4 -p \"http_uri\":  Discover Proxy and Initiate HTTP PUT Request");
100     OIC_LOG(INFO, TAG, "-t 5 -p \"http_uri\":  Discover Proxy and Initiate HTTP DELETE Request");
101 }
102
103 OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle,
104                                   OCClientResponse* clientResponse)
105 {
106     OC_UNUSED(ctx);
107     OC_UNUSED(handle);
108     if (clientResponse)
109     {
110         OIC_LOG_V(INFO, TAG, "StackResult: %u", clientResponse->result);
111         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
112         OIC_LOG(INFO, TAG, "=============> Put Response");
113     }
114     else
115     {
116         OIC_LOG_V(INFO, TAG, "%s received Null clientResponse", __func__);
117     }
118     return OC_STACK_DELETE_TRANSACTION;
119 }
120
121 OCStackApplicationResult postReqCB(void* ctx, OCDoHandle handle,
122                                    OCClientResponse* clientResponse)
123 {
124     OC_UNUSED(ctx);
125     OC_UNUSED(handle);
126     if (clientResponse)
127     {
128         OIC_LOG_V(INFO, TAG, "StackResult: %u", clientResponse->result);
129         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
130         OIC_LOG(INFO, TAG, "=============> Post Response");
131     }
132     else
133     {
134         OIC_LOG_V(INFO, TAG, "%s received Null clientResponse", __func__);
135     }
136     return OC_STACK_DELETE_TRANSACTION;
137 }
138
139 OCStackApplicationResult deleteReqCB(void* ctx,
140                                      OCDoHandle handle,
141                                      OCClientResponse* clientResponse)
142 {
143     OC_UNUSED(ctx);
144     OC_UNUSED(handle);
145     if (clientResponse)
146     {
147         OIC_LOG_V(INFO, TAG, "StackResult: %d",  clientResponse->result);
148         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
149         OIC_LOG(INFO, TAG, "=============> Delete Response");
150     }
151     else
152     {
153         OIC_LOG_V(INFO, TAG, "%s received Null clientResponse", __func__);
154     }
155     return OC_STACK_DELETE_TRANSACTION;
156 }
157
158 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
159                                   OCClientResponse* clientResponse)
160 {
161     OC_UNUSED(ctx);
162     OC_UNUSED(handle);
163     if (!clientResponse)
164     {
165         OIC_LOG_V(INFO, TAG, "%s received NULL clientResponse", __func__);
166         return OC_STACK_DELETE_TRANSACTION;
167     }
168
169     OIC_LOG_V(INFO, TAG, "StackResult: %d", clientResponse->result);
170     OIC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
171     OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
172     OIC_LOG(INFO, TAG, "=============> Get Response");
173
174     if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0)
175     {
176         OIC_LOG (INFO, TAG, "Received vendor specific options");
177         uint8_t i = 0;
178         OCHeaderOption* rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
179         for (i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
180         {
181             if (((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
182             {
183                 OIC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
184                           ((OCHeaderOption)rcvdOptions[i]).optionID);
185
186                 OIC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
187                                           ((OCHeaderOption)rcvdOptions[i]).optionLength);
188             }
189         }
190     }
191     return OC_STACK_DELETE_TRANSACTION;
192 }
193
194 int InitProxyRequest()
195 {
196     OIC_LOG(INFO, TAG, "InitProxyRequest");
197     OCHeaderOption option;
198     memset(&option, 0, sizeof(option));
199     option.protocolID = OC_COAP_ID;
200     option.optionID = OC_RSRVD_PROXY_OPTION_ID;
201     strncpy((char*)option.optionData, httpResource, sizeof(option.optionData));
202     size_t opLen = strlen(httpResource);
203     option.optionLength = opLen < sizeof(option.optionData) ? opLen : sizeof(option.optionData);
204
205     // A request with proxy uri shall not have resource uri
206     OCDoHandle handle;
207     OCCallbackData cbData;
208     cbData.context = NULL;
209     cbData.cd = NULL;
210     OCPayload* payload = NULL;
211     OCMethod method;
212
213     switch(testCase)
214     {
215         case TEST_DISCOVER_REQ:
216             return 1;
217         case TEST_GET_REQ:
218             method = OC_REST_GET;
219             cbData.cb = getReqCB;
220             break;
221         case TEST_POST_REQ:
222             method = OC_REST_POST;
223             cbData.cb = postReqCB;
224             payload = putPayload();
225             break;
226         case TEST_PUT_REQ:
227             method = OC_REST_PUT;
228             cbData.cb = putReqCB;
229             payload = putPayload();
230             break;
231         case TEST_DELETE_REQ:
232             method = OC_REST_DELETE;
233             cbData.cb = deleteReqCB;
234             break;
235         default:
236             return 1;
237     }
238
239     OCStackResult ret = OCDoResource(&handle, method, NULL, &serverAddr,
240                                      payload, connType, OC_LOW_QOS, &cbData, &option, 1);
241     if (ret != OC_STACK_OK)
242     {
243         OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
244         return 1;
245     }
246
247     return 0;
248 }
249
250 // This is a function called back when a device is discovered
251 OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
252                                         OCClientResponse* clientResponse)
253 {
254     OC_UNUSED(ctx);
255     OC_UNUSED(handle);
256     if (clientResponse)
257     {
258         OIC_LOG_V(INFO, TAG, "StackResult: %d", clientResponse->result);
259         OIC_LOG_V(INFO, TAG, "Discovered on %u", clientResponse->connType);
260         OIC_LOG_V(INFO, TAG, "Device =============> Discovered @ %s:%u",
261                               clientResponse->devAddr.addr,
262                               clientResponse->devAddr.port);
263         OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
264         serverAddr = clientResponse->devAddr;
265         connType = clientResponse->connType;
266         OCDiscoveryPayload* payload = (OCDiscoveryPayload*) clientResponse->payload;
267         if (!payload)
268         {
269             // Receive other discovery responses
270             return OC_STACK_KEEP_TRANSACTION;
271         }
272
273         int found = 0;
274         OCResourcePayload* resource = (OCResourcePayload*) payload->resources;
275         while (resource)
276         {
277             if (resource->uri && strcmp(resource->uri, OC_RSRVD_PROXY_URI) == 0)
278             {
279                 found = 1;
280                 break;
281             }
282             resource = resource->next;
283         }
284
285         if (!found)
286         {
287             OIC_LOG(INFO, TAG, "No proxy in payload");
288             return OC_STACK_KEEP_TRANSACTION;
289         }
290
291         OCEndpointPayload* eps = resource->eps;
292         while (NULL != eps)
293         {
294             if (eps->family & OC_FLAG_SECURE)
295             {
296                 if (0 == strcmp(eps->tps, "coaps"))
297                 {
298                     strncpy(serverAddr.addr, eps->addr, sizeof(serverAddr.addr));
299                     serverAddr.port = eps->port;
300                     serverAddr.flags = (OCTransportFlags)(eps->family | OC_SECURE);
301                     serverAddr.adapter = OC_ADAPTER_IP;
302                 }
303             }
304             eps = eps->next;
305         }
306
307         switch (testCase)
308         {
309             case TEST_DISCOVER_REQ:
310                 break;
311             case TEST_GET_REQ:
312             case TEST_POST_REQ:
313             case TEST_PUT_REQ:
314             case TEST_DELETE_REQ:
315                 InitProxyRequest();
316                 break;
317             default:
318                 PrintUsage();
319                 break;
320         }
321     }
322     else
323     {
324         OIC_LOG_V(INFO, TAG, "discoveryReqCB received Null clientResponse");
325     }
326     return OC_STACK_KEEP_TRANSACTION;
327 }
328
329 int InitDiscovery()
330 {
331     OCStackResult ret;
332     OCCallbackData cbData;
333     cbData.cb = discoveryReqCB;
334     cbData.context = NULL;
335     cbData.cd = NULL;
336
337     ret = OCDoResource(NULL, OC_REST_DISCOVER, discoveryQuery, NULL, 0, CT_DEFAULT,
338                        OC_LOW_QOS, &cbData, NULL, 0);
339     if (ret != OC_STACK_OK)
340     {
341         OIC_LOG_V(ERROR, TAG, "OCDoResource error [%d]", ret);
342     }
343     return ret;
344 }
345
346 FILE *client_fopen_devowner(const char *path, const char *mode)
347 {
348     if (0 == strcmp(path, OC_SECURITY_DB_DAT_FILE_NAME))
349     {
350         return fopen(CRED_FILE_DEVOWNER, mode);
351     }
352     else
353     {
354         return fopen(path, mode);
355     }
356 }
357
358 int main(int argc, char* argv[])
359 {
360     OCPersistentStorage ps = { client_fopen_devowner, fread, fwrite, fclose, unlink };
361     OCRegisterPersistentStorageHandler(&ps);
362
363     int opt;
364     while ((opt = getopt(argc, argv, "t:p:")) != -1)
365     {
366         switch (opt)
367         {
368             case 't':
369                 testCase = atoi(optarg);
370                 break;
371             case 'p':
372                 if (optarg)
373                 {
374                     /* Copy maximum upto "sizeof(httpResource) - 1" to safeguard against
375                        buffer overrun. Last byte is already NULL. */
376                     strncpy(httpResource, optarg, sizeof(httpResource) - 1);
377                 }
378                 break;
379             default:
380                 PrintUsage();
381                 return -1;
382         }
383     }
384
385     if ((testCase < TEST_DISCOVER_REQ || testCase >= MAX_TESTS) ||
386         (testCase != TEST_DISCOVER_REQ && httpResource[0] == '\0'))
387     {
388         PrintUsage();
389         return -1;
390     }
391
392     if (OCInit1(OC_CLIENT_SERVER, OC_DEFAULT_FLAGS, OC_DEFAULT_FLAGS) != OC_STACK_OK)
393     {
394         OIC_LOG(ERROR, TAG, "OCStack initialization error");
395         return -1;
396     }
397
398     if (InitDiscovery())
399     {
400         OIC_LOG(ERROR, TAG, "Failure initiating discovery");
401         return -1;
402     }
403
404     // Break from loop with Ctrl+C
405     OIC_LOG(INFO, TAG, "Entering proxy_client main loop.");
406     signal(SIGINT, handleSigInt);
407     while (!gQuitFlag)
408     {
409
410         if (OCProcess() != OC_STACK_OK)
411         {
412             OIC_LOG(ERROR, TAG, "OCStack process error");
413             return -1;
414         }
415
416         sleep(1);
417     }
418
419     OIC_LOG(INFO, TAG, "Exiting proxy_client main loop.");
420     if (OCStop() != OC_STACK_OK)
421     {
422         OIC_LOG(ERROR, TAG, "OCStack stop error");
423         return -1;
424     }
425
426     return 0;
427 }
428