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