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
21 #include "iotivity_config.h"
\r
26 #ifdef HAVE_UNISTD_H
\r
29 #ifdef HAVE_PTHREAD_H
\r
30 #include <pthread.h>
\r
34 #if defined(HAVE_WINDOWS_H)
\r
35 #include <windows.h>
\r
36 /** @todo stop-gap for naming issue. Windows.h does not like us to use ERROR */
\r
40 #endif // defined(HAVE_WINDOWS_H)
\r
41 #include "ocstack.h"
\r
43 #include "ocpayload.h"
\r
44 #include "payload_logging.h"
\r
45 #include "oic_malloc.h"
\r
46 #include "oic_string.h"
\r
49 #define TAG "occlient-directpairing"
\r
51 #define BOLD_BEGIN "\033[1m"
\r
52 #define RED_BEGIN "\033[1;31m"
\r
53 #define GREEN_BEGIN "\033[1;92m"
\r
54 #define COLOR_END "\033[0m"
\r
55 #define MAX_LINE (1024)
\r
56 #define DP_DISCOVERY_TIMEOUT 3 // 3 sec
\r
57 #define DP_PIN_LENGTH 8 // 8 digit
\r
59 static char DISCOVERY_QUERY[] = "%s/oic/res";
\r
61 //Secure Virtual Resource database for Iotivity Client application
\r
62 //It contains Client's Identity and the PSK credentials
\r
63 //of other devices which the client trusts
\r
64 static char CRED_FILE[] = "oic_svr_db_client_directpairing.dat";
\r
66 static const OCDPDev_t *discoveredDevs = NULL;
\r
67 static const OCDPDev_t *pairedDevs = NULL;
\r
71 //-----------------------------------------------------------------------------
\r
72 // Function prototype
\r
73 //-----------------------------------------------------------------------------
\r
78 //-----------------------------------------------------------------------------
\r
80 //-----------------------------------------------------------------------------
\r
82 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
\r
83 void handleSigInt(int signum)
\r
85 if (signum == SIGINT)
\r
91 const char *readline(const char *in, const char *defaultStr)
\r
93 static char rbuffer[MAX_LINE] = {0,};
\r
96 size_t in_len = strlen(in);
\r
97 for (size_t i=0; i<in_len; i++)
\r
99 fprintf(stdout, "%c", in[i]);
\r
102 if (NULL != (cptr = fgets(rbuffer, MAX_LINE, stdin)))
\r
104 /* kill preceding whitespace but leave \n so we're guaranteed to have something */
\r
105 /*while(*cptr == ' ' || *cptr == '\t')
\r
110 if ( (p = strchr(cptr, '\n')) != NULL )
\r
115 if (strlen(cptr)==0 && defaultStr)
\r
127 const char *getResult(OCStackResult result) {
\r
130 return "OC_STACK_OK";
\r
131 case OC_STACK_RESOURCE_CREATED:
\r
132 return "OC_STACK_RESOURCE_CREATED";
\r
133 case OC_STACK_RESOURCE_DELETED:
\r
134 return "OC_STACK_RESOURCE_DELETED";
\r
135 case OC_STACK_INVALID_URI:
\r
136 return "OC_STACK_INVALID_URI";
\r
137 case OC_STACK_INVALID_QUERY:
\r
138 return "OC_STACK_INVALID_QUERY";
\r
139 case OC_STACK_INVALID_IP:
\r
140 return "OC_STACK_INVALID_IP";
\r
141 case OC_STACK_INVALID_PORT:
\r
142 return "OC_STACK_INVALID_PORT";
\r
143 case OC_STACK_INVALID_CALLBACK:
\r
144 return "OC_STACK_INVALID_CALLBACK";
\r
145 case OC_STACK_INVALID_METHOD:
\r
146 return "OC_STACK_INVALID_METHOD";
\r
147 case OC_STACK_NO_MEMORY:
\r
148 return "OC_STACK_NO_MEMORY";
\r
149 case OC_STACK_COMM_ERROR:
\r
150 return "OC_STACK_COMM_ERROR";
\r
151 case OC_STACK_INVALID_PARAM:
\r
152 return "OC_STACK_INVALID_PARAM";
\r
153 case OC_STACK_NOTIMPL:
\r
154 return "OC_STACK_NOTIMPL";
\r
155 case OC_STACK_NO_RESOURCE:
\r
156 return "OC_STACK_NO_RESOURCE";
\r
157 case OC_STACK_RESOURCE_ERROR:
\r
158 return "OC_STACK_RESOURCE_ERROR";
\r
159 case OC_STACK_SLOW_RESOURCE:
\r
160 return "OC_STACK_SLOW_RESOURCE";
\r
161 case OC_STACK_NO_OBSERVERS:
\r
162 return "OC_STACK_NO_OBSERVERS";
\r
163 #ifdef WITH_PRESENCE
\r
164 case OC_STACK_PRESENCE_STOPPED:
\r
165 return "OC_STACK_PRESENCE_STOPPED";
\r
167 case OC_STACK_ERROR:
\r
168 return "OC_STACK_ERROR";
\r
174 OCDPDev_t* getDev(const OCDPDev_t* pList, const uint32_t dev_num)
\r
178 printf(" Device List is Empty..\n");
\r
182 OCDPDev_t* lst = (OCDPDev_t*)pList;
\r
183 for(size_t i=0; lst; )
\r
192 return NULL; // in here |lst| is always |NULL|
\r
195 int printList(const OCDPDev_t* pList)
\r
199 printf(" Device List is Empty..\n\n");
\r
203 const OCDPDev_t* lst = pList;
\r
207 printf(" [%d] ", ++lst_cnt);
\r
208 for(int i=0; i<UUID_IDENTITY_SIZE; i++)
\r
210 fprintf(stdout, "%c", (char)lst->deviceID.id[i]);
\r
220 bool printPairingMethod(const OCDPDev_t* pDev)
\r
222 printf("\n * List of supported pairing method\n");
\r
224 if(!pDev || false == pDev->edp)
\r
226 printf(" Invalid device or Not support direct-pairing..\n\n");
\r
230 if(!pDev->prm || 0 == pDev->prmLen)
\r
232 printf(" Not exist any support method..\n\n");
\r
236 bool bAvailable = true;
\r
237 for(size_t i=0; i<pDev->prmLen; i++)
\r
239 printf(" [%ld] ", i+1);
\r
240 switch (pDev->prm[i])
\r
242 case DP_PRE_CONFIGURED:
\r
243 printf("Pre-Configured PIN");
\r
245 case DP_RANDOM_PIN:
\r
246 printf("Random PIN");
\r
249 printf("NOT Allowed (%d)", pDev->prm[i]);
\r
250 bAvailable = false;
\r
260 // This is a function called back when a device is discovered
\r
261 OCStackApplicationResult discoveryReqCB(void*, OCDoHandle,
\r
262 OCClientResponse * clientResponse)
\r
264 OIC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
\r
266 if (clientResponse)
\r
268 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
269 OIC_LOG_V(INFO, TAG,
\r
270 "Device =============> Discovered @ %s:%d",
\r
271 clientResponse->devAddr.addr,
\r
272 clientResponse->devAddr.port);
\r
274 if (clientResponse->result == OC_STACK_OK)
\r
276 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
280 return OC_STACK_DELETE_TRANSACTION;
\r
284 // This is a function called back when direct-pairing status is changed
\r
285 void pairingReqCB(void *ctx, OCDPDev_t* peer, OCStackResult result)
\r
287 OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing establishment\n");
\r
290 if (OC_STACK_OK == result)
\r
292 OIC_LOG_V(INFO, TAG,
\r
293 "Direct-Pairing SUCCESS =============> Target @ %s:%d\n",
\r
294 peer->endpoint.addr,
\r
295 peer->endpoint.port);
\r
299 OIC_LOG(ERROR, TAG, "Direct-Pairing FAILED..\n");
\r
303 OCStackApplicationResult getReqCB(void * ctx, OCDoHandle handle, OCClientResponse *clientResponse)
\r
305 OIC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
\r
309 if (clientResponse)
\r
311 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
312 OIC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
\r
313 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
314 if ((OCSecurityPayload*)clientResponse->payload)
\r
316 OIC_LOG(INFO, TAG, PCF("=============> Get Response"));
\r
319 return OC_STACK_DELETE_TRANSACTION;
\r
322 int DeviceDiscovery()
\r
325 OCCallbackData cbData;
\r
326 char queryUri[200];
\r
327 char ipaddr[100] = { '\0' };
\r
329 snprintf(queryUri, sizeof (queryUri), DISCOVERY_QUERY, ipaddr);
\r
331 cbData.cb = discoveryReqCB;
\r
332 cbData.context = NULL;
\r
335 /* Start a discovery query*/
\r
336 OIC_LOG_V(INFO, TAG, "Resource Discovery : %s\n", queryUri);
\r
338 ret = OCDoRequest(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,
\r
339 OC_LOW_QOS, &cbData, NULL, 0);
\r
340 if (ret != OC_STACK_OK)
\r
342 OIC_LOG(ERROR, TAG, "OCStack resource error");
\r
347 OCStackResult DirectPairingDiscovery()
\r
349 // initiate direct pairing discovery
\r
350 OIC_LOG(INFO, TAG, " Discovering Only Owned Devices on Network..");
\r
351 discoveredDevs = OCDiscoverDirectPairingDevices(DP_DISCOVERY_TIMEOUT);
\r
352 if(NULL == discoveredDevs)
\r
354 OIC_LOG(ERROR, TAG, "OCDiscoverDirectPairingDevices API error");
\r
355 return OC_STACK_ERROR;
\r
358 // display the discovered unowned list
\r
359 printf(" > Discovered Direct-Pairing Support Devices\n");
\r
360 printList(discoveredDevs);
\r
362 return OC_STACK_OK;
\r
365 OCStackResult DoDirectPairing(OCDPDev_t* peer, OCPrm_t pmSel, char *pinNumber)
\r
367 if (NULL == peer || NULL == pinNumber)
\r
369 OIC_LOG(ERROR, TAG, "invalid parameter");
\r
370 return OC_STACK_INVALID_PARAM;
\r
373 // start direct pairing
\r
374 OIC_LOG(INFO, TAG, " Start Direct Pairing..");
\r
375 if(OC_STACK_OK != OCDoDirectPairing(NULL, peer, pmSel, pinNumber, pairingReqCB))
\r
377 OIC_LOG(ERROR, TAG, "OCDoDirectPairing API error");
\r
378 return OC_STACK_ERROR;
\r
381 return OC_STACK_OK;
\r
384 OCStackResult SendGetRequest(OCDPDev_t* peer)
\r
386 OIC_LOG(INFO, TAG, "Send Get REQ to Led server");
\r
388 char szQueryUri[] = "/a/led";
\r
390 OCCallbackData cbData;
\r
391 OCDevAddr endpoint;
\r
394 memcpy(&endpoint, &peer->endpoint, sizeof(OCDevAddr));
\r
395 endpoint.port = peer->securePort;
\r
396 endpoint.flags = (OCTransportFlags)(endpoint.flags | OC_SECURE);
\r
398 cbData.cb = getReqCB;
\r
399 cbData.context = NULL;
\r
402 OIC_LOG(INFO, TAG, "Request to /a/light ");
\r
403 ret = OCDoRequest(&handle, OC_REST_GET, szQueryUri,
\r
404 &endpoint, NULL, peer->connType, OC_LOW_QOS, &cbData, NULL, 0);
\r
405 if (ret != OC_STACK_OK)
\r
407 OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, OC_REST_GET);
\r
413 FILE* client_fopen(const char *path, const char *mode)
\r
416 return fopen(CRED_FILE, mode);
\r
419 void *CLInterface(void *data)
\r
421 printf(RED_BEGIN "#Ready to operation ('h' for help)#\n" COLOR_END);
\r
425 char query[MAX_LINE] = {0};
\r
426 const char prompt[] = BOLD_BEGIN "IoTivity-DP#" COLOR_END" ";
\r
427 const char* helpmsg[6] = {
\r
428 GREEN_BEGIN "# h (or help) : show help message" COLOR_END,
\r
429 GREEN_BEGIN "# dd (DP device discovery) : discover Direct-Pairing devices" COLOR_END,
\r
430 GREEN_BEGIN "# dp (start Direct-Pairing) : negotiate DP method & start Direct-Pairing" COLOR_END,
\r
431 GREEN_BEGIN "# sd (send data) : send data to device" COLOR_END,
\r
432 GREEN_BEGIN "# ll (list all device) : list all discovered/paired devices" COLOR_END,
\r
433 GREEN_BEGIN "# q (quit) : quit test" COLOR_END,
\r
436 for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)
\r
438 fprintf(stderr, "%s\n", helpmsg[i]);
\r
445 const char *input = readline(prompt, NULL);
\r
450 strncpy(query, input, MAX_LINE);
\r
451 if (!strlen(query))
\r
455 else if (!strcmp(query, "h") || !strcmp(query, "help"))
\r
457 for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)
\r
459 fprintf(stderr, "%s\n", helpmsg[i]);
\r
465 if (!strcmp(query, "dd"))
\r
467 OIC_LOG(INFO, TAG, "- Direct-Pairing device discovery -");
\r
469 ret = DirectPairingDiscovery();
\r
470 if (OC_STACK_OK != ret)
\r
472 OIC_LOG(ERROR, TAG, "Error in DirectPairingDiscovery()");
\r
475 else if (!strcmp(query, "dp"))
\r
477 OIC_LOG(INFO, TAG, "- Negotiate DP method & Start Direct-Pairing -");
\r
479 printf("\n * List of discovered device\n");
\r
480 printList(discoveredDevs);
\r
483 OCDPDev_t *peer = NULL;
\r
485 input = readline(" > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);
\r
486 if (!input || !strlen(input))
\r
491 peerIdx = strtol(input, &ptr, 10);
\r
493 peer = getDev(discoveredDevs, (uint32_t)peerIdx);
\r
496 OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");
\r
500 // get pairing method
\r
502 OCPrm_t pmSel = DP_NOT_ALLOWED;
\r
503 if (false == printPairingMethod(peer))
\r
505 OIC_LOG(ERROR, TAG, "Target does not support the Direct-Pairing");
\r
508 input = readline(" > Enter pairing method: ", NULL);
\r
509 if (!input || !strlen(input))
\r
513 pmIdx = strtol(input, &ptr, 10);
\r
515 if (0 >= pmIdx || peer->prmLen+1 < (size_t)pmIdx)
\r
517 OIC_LOG(ERROR, TAG, "Invalid mode selection");
\r
520 pmSel = peer->prm[pmIdx-1];
\r
523 char pinNumber[DP_PIN_LENGTH+1];
\r
524 input = readline(" > Enter PIN Number for authentication (ex - '00000000' [8 digit] ): ", NULL);
\r
525 if (!input || DP_PIN_LENGTH != strlen(input))
\r
527 OIC_LOG(ERROR, TAG, "Invalid PIN");
\r
530 sscanf(input, "%8s", pinNumber);
\r
533 ret = DoDirectPairing(peer, pmSel, pinNumber);
\r
534 if (OC_STACK_OK != ret)
\r
536 OIC_LOG(ERROR, TAG, "Error in DoDirectPairing()");
\r
539 else if (!strcmp(query, "sd"))
\r
541 OIC_LOG(INFO, TAG, "- Send data(GET Request) to device(led server) -");
\r
543 //pairedDevs = OCGetDirectPairedDevices();
\r
544 //printList(pairedDevs);
\r
545 printList(discoveredDevs);
\r
548 OCDPDev_t *peer = NULL;
\r
550 input = readline(" > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);
\r
551 if (!input || !strlen(input))
\r
556 peerIdx = strtol(input, &ptr, 10);
\r
558 //peer = getDev(pairedDevs, peerIdx);
\r
559 peer = getDev(discoveredDevs, (uint32_t)peerIdx);
\r
562 OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");
\r
567 ret = SendGetRequest(peer);
\r
568 if (OC_STACK_OK != ret)
\r
570 OIC_LOG(ERROR, TAG, "Error in SendGetRequest()");
\r
573 else if (!strcmp(query, "ll"))
\r
575 OIC_LOG(INFO, TAG, "- List all discovered and paired devices) -");
\r
577 printf(" > List of discovered devices\n");
\r
578 printList(discoveredDevs);
\r
581 printf(" > List of paired devices\n");
\r
582 pairedDevs = OCGetDirectPairedDevices();
\r
583 printList(pairedDevs);
\r
586 else if (!strcmp(query, "q"))
\r
600 struct timespec timeout;
\r
602 // Initialize Persistent Storage for SVR database
\r
603 OCPersistentStorage ps = { client_fopen, fread, fwrite, fclose, unlink };
\r
604 OCRegisterPersistentStorageHandler(&ps);
\r
606 /* Initialize OCStack*/
\r
607 if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
\r
609 OIC_LOG(ERROR, TAG, "OCStack init error");
\r
613 // DeviceDiscovery();
\r
615 timeout.tv_sec = 0;
\r
616 timeout.tv_nsec = 100000000L;
\r
618 // Break from loop with Ctrl+C
\r
619 OIC_LOG(INFO, TAG, "Entering occlient main loop...");
\r
620 signal(SIGINT, handleSigInt);
\r
624 pthread_t p_thread;
\r
625 thr_id = pthread_create(&p_thread, NULL, CLInterface, (void *)NULL);
\r
628 OIC_LOG(ERROR, TAG, "create CLI Thread error");
\r
635 if (OCProcess() != OC_STACK_OK)
\r
637 OIC_LOG(ERROR, TAG, "OCStack process error");
\r
641 #if defined(_WIN32)
\r
644 nanosleep(&timeout, NULL);
\r
645 #endif // defined(_WIN32)
\r
648 OIC_LOG(INFO, TAG, "Exiting occlient main loop...");
\r
650 if (OCStop() != OC_STACK_OK)
\r
652 OIC_LOG(ERROR, TAG, "OCStack stop error");
\r