1 //******************************************************************
\r
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
\r
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
7 // Licensed under the Apache License, Version 2.0 (the "License");
\r
8 // you may not use this file except in compliance with the License.
\r
9 // You may obtain a copy of the License at
\r
11 // http://www.apache.org/licenses/LICENSE-2.0
\r
13 // Unless required by applicable law or agreed to in writing, software
\r
14 // distributed under the License is distributed on an "AS IS" BASIS,
\r
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 // See the License for the specific language governing permissions and
\r
17 // limitations under the License.
\r
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
25 #ifdef HAVE_UNISTD_H
\r
28 #ifdef HAVE_PTHREAD_H
\r
29 #include <pthread.h>
\r
34 #include <windows.h>
\r
35 /** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */
\r
39 #endif // defined(_WIN32)
\r
40 #include "ocstack.h"
\r
42 #include "ocpayload.h"
\r
43 #include "payload_logging.h"
\r
44 #include "oic_malloc.h"
\r
45 #include "oic_string.h"
\r
48 #define TAG "occlient-directpairing"
\r
50 #define BOLD_BEGIN "\033[1m"
\r
51 #define RED_BEGIN "\033[1;31m"
\r
52 #define GREEN_BEGIN "\033[1;92m"
\r
53 #define COLOR_END "\033[0m"
\r
54 #define MAX_LINE (1024)
\r
55 #define DP_DISCOVERY_TIMEOUT 3 // 3 sec
\r
56 #define DP_PIN_LENGTH 8 // 8 digit
\r
58 static char DISCOVERY_QUERY[] = "%s/oic/res";
\r
60 //Secure Virtual Resource database for Iotivity Client application
\r
61 //It contains Client's Identity and the PSK credentials
\r
62 //of other devices which the client trusts
\r
63 static char CRED_FILE[] = "oic_svr_db_client_directpairing.dat";
65 static const OCDPDev_t *discoveredDevs = NULL;
\r
66 static const OCDPDev_t *pairedDevs = NULL;
\r
70 //-----------------------------------------------------------------------------
\r
71 // Function prototype
\r
72 //-----------------------------------------------------------------------------
\r
77 //-----------------------------------------------------------------------------
\r
79 //-----------------------------------------------------------------------------
\r
81 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
\r
82 void handleSigInt(int signum)
\r
84 if (signum == SIGINT)
\r
90 const char *readline(const char *in, const char *defaultStr)
\r
92 static char rbuffer[MAX_LINE] = {0,};
\r
95 size_t in_len = strlen(in);
\r
96 for (size_t i=0; i<in_len; i++)
\r
98 fprintf(stdout, "%c", in[i]);
\r
101 if (NULL != (cptr = fgets(rbuffer, MAX_LINE, stdin)))
\r
103 /* kill preceding whitespace but leave \n so we're guaranteed to have something */
\r
104 /*while(*cptr == ' ' || *cptr == '\t')
\r
109 if ( (p = strchr(cptr, '\n')) != NULL )
\r
114 if (strlen(cptr)==0 && defaultStr)
\r
126 const char *getResult(OCStackResult result) {
\r
129 return "OC_STACK_OK";
\r
130 case OC_STACK_RESOURCE_CREATED:
\r
131 return "OC_STACK_RESOURCE_CREATED";
\r
132 case OC_STACK_RESOURCE_DELETED:
\r
133 return "OC_STACK_RESOURCE_DELETED";
\r
134 case OC_STACK_INVALID_URI:
\r
135 return "OC_STACK_INVALID_URI";
\r
136 case OC_STACK_INVALID_QUERY:
\r
137 return "OC_STACK_INVALID_QUERY";
\r
138 case OC_STACK_INVALID_IP:
\r
139 return "OC_STACK_INVALID_IP";
\r
140 case OC_STACK_INVALID_PORT:
\r
141 return "OC_STACK_INVALID_PORT";
\r
142 case OC_STACK_INVALID_CALLBACK:
\r
143 return "OC_STACK_INVALID_CALLBACK";
\r
144 case OC_STACK_INVALID_METHOD:
\r
145 return "OC_STACK_INVALID_METHOD";
\r
146 case OC_STACK_NO_MEMORY:
\r
147 return "OC_STACK_NO_MEMORY";
\r
148 case OC_STACK_COMM_ERROR:
\r
149 return "OC_STACK_COMM_ERROR";
\r
150 case OC_STACK_INVALID_PARAM:
\r
151 return "OC_STACK_INVALID_PARAM";
\r
152 case OC_STACK_NOTIMPL:
\r
153 return "OC_STACK_NOTIMPL";
\r
154 case OC_STACK_NO_RESOURCE:
\r
155 return "OC_STACK_NO_RESOURCE";
\r
156 case OC_STACK_RESOURCE_ERROR:
\r
157 return "OC_STACK_RESOURCE_ERROR";
\r
158 case OC_STACK_SLOW_RESOURCE:
\r
159 return "OC_STACK_SLOW_RESOURCE";
\r
160 case OC_STACK_NO_OBSERVERS:
\r
161 return "OC_STACK_NO_OBSERVERS";
\r
162 #ifdef WITH_PRESENCE
\r
163 case OC_STACK_PRESENCE_STOPPED:
\r
164 return "OC_STACK_PRESENCE_STOPPED";
\r
166 case OC_STACK_ERROR:
\r
167 return "OC_STACK_ERROR";
\r
173 OCDPDev_t* getDev(const OCDPDev_t* pList, const uint32_t dev_num)
\r
177 printf(" Device List is Empty..\n");
\r
181 OCDPDev_t* lst = (OCDPDev_t*)pList;
\r
182 for(size_t i=0; lst; )
\r
191 return NULL; // in here |lst| is always |NULL|
\r
194 int printList(const OCDPDev_t* pList)
\r
198 printf(" Device List is Empty..\n\n");
\r
202 const OCDPDev_t* lst = pList;
\r
206 printf(" [%d] ", ++lst_cnt);
\r
207 for(int i=0; i<UUID_IDENTITY_SIZE; i++)
\r
209 fprintf(stdout, "%c", (char)lst->deviceID.id[i]);
\r
219 bool printPairingMethod(const OCDPDev_t* pDev)
\r
221 printf("\n * List of supported pairing method\n");
\r
223 if(!pDev || false == pDev->edp)
\r
225 printf(" Invalid device or Not support direct-pairing..\n\n");
\r
229 if(!pDev->prm || 0 == pDev->prmLen)
\r
231 printf(" Not exist any support method..\n\n");
\r
235 bool bAvailable = true;
\r
236 for(size_t i=0; i<pDev->prmLen; i++)
\r
238 printf(" [%ld] ", i+1);
\r
239 switch (pDev->prm[i])
\r
241 case DP_PRE_CONFIGURED:
\r
242 printf("Pre-Configured PIN");
\r
244 case DP_RANDOM_PIN:
\r
245 printf("Random PIN");
\r
248 printf("NOT Allowed (%d)", pDev->prm[i]);
\r
249 bAvailable = false;
\r
259 // This is a function called back when a device is discovered
\r
260 OCStackApplicationResult discoveryReqCB(void*, OCDoHandle,
\r
261 OCClientResponse * clientResponse)
\r
263 OIC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
\r
265 if (clientResponse)
\r
267 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
268 OIC_LOG_V(INFO, TAG,
\r
269 "Device =============> Discovered @ %s:%d",
\r
270 clientResponse->devAddr.addr,
\r
271 clientResponse->devAddr.port);
\r
273 if (clientResponse->result == OC_STACK_OK)
\r
275 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
279 return OC_STACK_DELETE_TRANSACTION;
\r
283 // This is a function called back when direct-pairing status is changed
\r
284 void pairingReqCB(OCDPDev_t* peer, OCStackResult result)
\r
286 OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing establishment\n");
\r
288 if (OC_STACK_OK == result)
\r
290 OIC_LOG_V(INFO, TAG,
\r
291 "Direct-Pairing SUCCESS =============> Target @ %s:%d\n",
\r
292 peer->endpoint.addr,
\r
293 peer->endpoint.port);
\r
297 OIC_LOG(ERROR, TAG, "Direct-Pairing FAILED..\n");
\r
301 OCStackApplicationResult getReqCB(void * ctx, OCDoHandle handle, OCClientResponse *clientResponse)
\r
303 OIC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
\r
307 if (clientResponse)
\r
309 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
310 OIC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
\r
311 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
312 if ((OCSecurityPayload*)clientResponse->payload)
\r
314 OIC_LOG(INFO, TAG, PCF("=============> Get Response"));
\r
317 return OC_STACK_DELETE_TRANSACTION;
\r
320 int DeviceDiscovery()
\r
323 OCCallbackData cbData;
\r
324 char queryUri[200];
\r
325 char ipaddr[100] = { '\0' };
\r
327 snprintf(queryUri, sizeof (queryUri), DISCOVERY_QUERY, ipaddr);
\r
329 cbData.cb = discoveryReqCB;
\r
330 cbData.context = NULL;
\r
333 /* Start a discovery query*/
\r
334 OIC_LOG_V(INFO, TAG, "Resource Discovery : %s\n", queryUri);
\r
336 ret = OCDoResource(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,
\r
337 OC_LOW_QOS, &cbData, NULL, 0);
\r
338 if (ret != OC_STACK_OK)
\r
340 OIC_LOG(ERROR, TAG, "OCStack resource error");
\r
345 OCStackResult DirectPairingDiscovery()
\r
347 // initiate direct pairing discovery
\r
348 OIC_LOG(INFO, TAG, " Discovering Only Owned Devices on Network..");
\r
349 discoveredDevs = OCDiscoverDirectPairingDevices(DP_DISCOVERY_TIMEOUT);
\r
350 if(NULL == discoveredDevs)
\r
352 OIC_LOG(ERROR, TAG, "OCDiscoverDirectPairingDevices API error");
\r
353 return OC_STACK_ERROR;
\r
356 // display the discovered unowned list
\r
357 printf(" > Discovered Direct-Pairing Support Devices\n");
\r
358 printList(discoveredDevs);
\r
360 return OC_STACK_OK;
\r
363 OCStackResult DoDirectPairing(OCDPDev_t* peer, OCPrm_t pmSel, char *pinNumber)
\r
365 if (NULL == peer || NULL == pinNumber)
\r
367 OIC_LOG(ERROR, TAG, "invalid parameter");
\r
368 return OC_STACK_INVALID_PARAM;
\r
371 // start direct pairing
\r
372 OIC_LOG(INFO, TAG, " Start Direct Pairing..");
\r
373 if(OC_STACK_OK != OCDoDirectPairing(peer, pmSel, pinNumber, pairingReqCB))
\r
375 OIC_LOG(ERROR, TAG, "OCDoDirectPairing API error");
\r
376 return OC_STACK_ERROR;
\r
379 return OC_STACK_OK;
\r
382 OCStackResult SendGetRequest(OCDPDev_t* peer)
\r
384 OIC_LOG(INFO, TAG, "Send Get REQ to Led server");
\r
386 char szQueryUri[] = "/a/led";
\r
388 OCCallbackData cbData;
\r
389 OCDevAddr endpoint;
\r
392 memcpy(&endpoint, &peer->endpoint, sizeof(OCDevAddr));
\r
393 endpoint.port = peer->securePort;
\r
394 endpoint.flags = (OCTransportFlags)(endpoint.flags | OC_SECURE);
\r
396 cbData.cb = getReqCB;
\r
397 cbData.context = NULL;
\r
400 OIC_LOG(INFO, TAG, "Request to /a/light ");
\r
401 ret = OCDoResource(&handle, OC_REST_GET, szQueryUri,
\r
402 &endpoint, NULL, peer->connType, OC_LOW_QOS, &cbData, NULL, 0);
\r
403 if (ret != OC_STACK_OK)
\r
405 OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, OC_REST_GET);
\r
411 FILE* client_fopen(const char *path, const char *mode)
\r
414 return fopen(CRED_FILE, mode);
\r
417 void *CLInterface(void *data)
\r
419 printf(RED_BEGIN"#Ready to operation ('h' for help)#\n"COLOR_END);
\r
423 char query[MAX_LINE] = {0,};
\r
424 const char prompt[] = BOLD_BEGIN"IoTivity-DP#"COLOR_END" ";
\r
425 const char* helpmsg[6] = {
\r
426 GREEN_BEGIN"# h (or help) : show help message"COLOR_END,
\r
427 GREEN_BEGIN"# dd (DP device discovery) : discover Direct-Pairing devices"COLOR_END,
\r
428 GREEN_BEGIN"# dp (start Direct-Pairing) : negotiate DP method & start Direct-Pairing"COLOR_END,
\r
429 GREEN_BEGIN"# sd (send data) : send data to device"COLOR_END,
\r
430 GREEN_BEGIN"# ll (list all device) : list all discovered/paired devices"COLOR_END,
\r
431 GREEN_BEGIN"# q (quit) : quit test"COLOR_END,
\r
434 for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)
\r
436 fprintf(stderr, "%s\n", helpmsg[i]);
\r
443 const char *input = readline(prompt, NULL);
\r
448 strncpy(query, input, MAX_LINE);
\r
449 if (!strlen(query))
\r
453 else if (!strcmp(query, "h") || !strcmp(query, "help"))
\r
455 for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)
\r
457 fprintf(stderr, "%s\n", helpmsg[i]);
\r
463 if (!strcmp(query, "dd"))
\r
465 OIC_LOG(INFO, TAG, "- Direct-Pairing device discovery -");
\r
467 ret = DirectPairingDiscovery();
\r
468 if (OC_STACK_OK != ret)
\r
470 OIC_LOG(ERROR, TAG, "Error in DirectPairingDiscovery()");
\r
473 else if (!strcmp(query, "dp"))
\r
475 OIC_LOG(INFO, TAG, "- Negotiate DP method & Start Direct-Pairing -");
\r
477 printf("\n * List of discovered device\n");
\r
478 printList(discoveredDevs);
\r
481 OCDPDev_t *peer = NULL;
\r
483 input = readline(" > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);
\r
484 if (!input || !strlen(input))
\r
489 peerIdx = strtol(input, &ptr, 10);
\r
491 peer = getDev(discoveredDevs, (uint32_t)peerIdx);
\r
494 OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");
\r
498 // get pairing method
\r
500 OCPrm_t pmSel = DP_NOT_ALLOWED;
\r
501 if (false == printPairingMethod(peer))
\r
503 OIC_LOG(ERROR, TAG, "Target does not support the Direct-Pairing");
\r
506 input = readline(" > Enter pairing method: ", NULL);
\r
507 if (!input || !strlen(input))
\r
511 pmIdx = strtol(input, &ptr, 10);
\r
513 if (0 >= pmIdx || peer->prmLen+1 < (size_t)pmIdx)
\r
515 OIC_LOG(ERROR, TAG, "Invalid mode selection");
\r
518 pmSel = peer->prm[pmIdx-1];
\r
521 char pinNumber[DP_PIN_LENGTH+1];
\r
522 input = readline(" > Enter PIN Number for authentication (ex - '00000000' [8 digit] ): ", NULL);
\r
523 if (!input || DP_PIN_LENGTH != strlen(input))
\r
525 OIC_LOG(ERROR, TAG, "Invalid PIN");
\r
528 sscanf(input, "%8s", pinNumber);
531 ret = DoDirectPairing(peer, pmSel, pinNumber);
\r
532 if (OC_STACK_OK != ret)
\r
534 OIC_LOG(ERROR, TAG, "Error in DoDirectPairing()");
\r
537 else if (!strcmp(query, "sd"))
\r
539 OIC_LOG(INFO, TAG, "- Send data(GET Request) to device(led server) -");
\r
541 //pairedDevs = OCGetDirectPairedDevices();
\r
542 //printList(pairedDevs);
\r
543 printList(discoveredDevs);
\r
546 OCDPDev_t *peer = NULL;
\r
548 input = readline(" > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);
\r
549 if (!input || !strlen(input))
\r
554 peerIdx = strtol(input, &ptr, 10);
\r
556 //peer = getDev(pairedDevs, peerIdx);
\r
557 peer = getDev(discoveredDevs, (uint32_t)peerIdx);
\r
560 OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");
\r
565 ret = SendGetRequest(peer);
\r
566 if (OC_STACK_OK != ret)
\r
568 OIC_LOG(ERROR, TAG, "Error in SendGetRequest()");
\r
571 else if (!strcmp(query, "ll"))
\r
573 OIC_LOG(INFO, TAG, "- List all discovered and paired devices) -");
\r
575 printf(" > List of discovered devices\n");
\r
576 printList(discoveredDevs);
\r
579 printf(" > List of paired devices\n");
\r
580 pairedDevs = OCGetDirectPairedDevices();
\r
581 printList(pairedDevs);
\r
584 else if (!strcmp(query, "q"))
\r
598 struct timespec timeout;
\r
600 // Initialize Persistent Storage for SVR database
\r
601 OCPersistentStorage ps = { client_fopen, fread, fwrite, fclose, unlink };
\r
602 OCRegisterPersistentStorageHandler(&ps);
\r
604 /* Initialize OCStack*/
\r
605 if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
\r
607 OIC_LOG(ERROR, TAG, "OCStack init error");
\r
611 // DeviceDiscovery();
\r
613 timeout.tv_sec = 0;
\r
614 timeout.tv_nsec = 100000000L;
\r
616 // Break from loop with Ctrl+C
\r
617 OIC_LOG(INFO, TAG, "Entering occlient main loop...");
\r
618 signal(SIGINT, handleSigInt);
\r
622 pthread_t p_thread;
\r
623 thr_id = pthread_create(&p_thread, NULL, CLInterface, (void *)NULL);
\r
626 OIC_LOG(ERROR, TAG, "create CLI Thread error");
\r
633 if (OCProcess() != OC_STACK_OK)
\r
635 OIC_LOG(ERROR, TAG, "OCStack process error");
\r
639 #if defined(_WIN32)
\r
642 nanosleep(&timeout, NULL);
\r
643 #endif // defined(_WIN32)
\r
646 OIC_LOG(INFO, TAG, "Exiting occlient main loop...");
\r
648 if (OCStop() != OC_STACK_OK)
\r
650 OIC_LOG(ERROR, TAG, "OCStack stop error");
\r