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
26 #include <pthread.h>
\r
29 #include "ocstack.h"
\r
31 #include "ocpayload.h"
\r
32 #include "payload_logging.h"
\r
33 #include "oic_malloc.h"
\r
34 #include "oic_string.h"
\r
37 #define TAG "occlient-directpairing"
\r
39 #define BOLD_BEGIN "\033[1m"
\r
40 #define RED_BEGIN "\033[1;31m"
\r
41 #define GREEN_BEGIN "\033[1;92m"
\r
42 #define COLOR_END "\033[0m"
\r
43 #define MAX_LINE (1024)
\r
44 #define DP_DISCOVERY_TIMEOUT 3 // 3 sec
\r
45 #define DP_PIN_LENGTH 8 // 8 digit
\r
47 static char DISCOVERY_QUERY[] = "%s/oic/res";
\r
49 //Secure Virtual Resource database for Iotivity Client application
\r
50 //It contains Client's Identity and the PSK credentials
\r
51 //of other devices which the client trusts
\r
52 static char CRED_FILE[] = "oic_svr_db_client_directpairing.json";
\r
54 static const OCDPDev_t *discoveredDevs = NULL;
\r
55 static const OCDPDev_t *pairedDevs = NULL;
\r
59 //-----------------------------------------------------------------------------
\r
60 // Function prototype
\r
61 //-----------------------------------------------------------------------------
\r
66 //-----------------------------------------------------------------------------
\r
68 //-----------------------------------------------------------------------------
\r
70 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
\r
71 void handleSigInt(int signum)
\r
73 if (signum == SIGINT)
\r
79 const char *readline(const char *in, const char *defaultStr)
\r
81 static char rbuffer[MAX_LINE] = {0,};
\r
84 size_t in_len = strlen(in);
\r
85 for (size_t i=0; i<in_len; i++)
\r
87 fprintf(stdout, "%c", in[i]);
\r
90 if (NULL != (cptr = fgets(rbuffer, MAX_LINE, stdin)))
\r
92 /* kill preceding whitespace but leave \n so we're guaranteed to have something */
\r
93 /*while(*cptr == ' ' || *cptr == '\t')
\r
98 if ( (p = strchr(cptr, '\n')) != NULL )
\r
103 if (strlen(cptr)==0 && defaultStr)
\r
115 const char *getResult(OCStackResult result) {
\r
118 return "OC_STACK_OK";
\r
119 case OC_STACK_RESOURCE_CREATED:
\r
120 return "OC_STACK_RESOURCE_CREATED";
\r
121 case OC_STACK_RESOURCE_DELETED:
\r
122 return "OC_STACK_RESOURCE_DELETED";
\r
123 case OC_STACK_INVALID_URI:
\r
124 return "OC_STACK_INVALID_URI";
\r
125 case OC_STACK_INVALID_QUERY:
\r
126 return "OC_STACK_INVALID_QUERY";
\r
127 case OC_STACK_INVALID_IP:
\r
128 return "OC_STACK_INVALID_IP";
\r
129 case OC_STACK_INVALID_PORT:
\r
130 return "OC_STACK_INVALID_PORT";
\r
131 case OC_STACK_INVALID_CALLBACK:
\r
132 return "OC_STACK_INVALID_CALLBACK";
\r
133 case OC_STACK_INVALID_METHOD:
\r
134 return "OC_STACK_INVALID_METHOD";
\r
135 case OC_STACK_NO_MEMORY:
\r
136 return "OC_STACK_NO_MEMORY";
\r
137 case OC_STACK_COMM_ERROR:
\r
138 return "OC_STACK_COMM_ERROR";
\r
139 case OC_STACK_INVALID_PARAM:
\r
140 return "OC_STACK_INVALID_PARAM";
\r
141 case OC_STACK_NOTIMPL:
\r
142 return "OC_STACK_NOTIMPL";
\r
143 case OC_STACK_NO_RESOURCE:
\r
144 return "OC_STACK_NO_RESOURCE";
\r
145 case OC_STACK_RESOURCE_ERROR:
\r
146 return "OC_STACK_RESOURCE_ERROR";
\r
147 case OC_STACK_SLOW_RESOURCE:
\r
148 return "OC_STACK_SLOW_RESOURCE";
\r
149 case OC_STACK_NO_OBSERVERS:
\r
150 return "OC_STACK_NO_OBSERVERS";
\r
151 #ifdef WITH_PRESENCE
\r
152 case OC_STACK_PRESENCE_STOPPED:
\r
153 return "OC_STACK_PRESENCE_STOPPED";
\r
155 case OC_STACK_ERROR:
\r
156 return "OC_STACK_ERROR";
\r
162 OCDPDev_t* getDev(const OCDPDev_t* pList, const uint32_t dev_num)
\r
166 printf(" Device List is Empty..\n");
\r
170 OCDPDev_t* lst = (OCDPDev_t*)pList;
\r
171 for(size_t i=0; lst; )
\r
180 return NULL; // in here |lst| is always |NULL|
\r
183 int printList(const OCDPDev_t* pList)
\r
187 printf(" Device List is Empty..\n\n");
\r
191 const OCDPDev_t* lst = pList;
\r
195 printf(" [%d] ", ++lst_cnt);
\r
196 for(int i=0; i<UUID_IDENTITY_SIZE; i++)
\r
198 fprintf(stdout, "%c", (char)lst->deviceID.id[i]);
\r
208 bool printPairingMethod(const OCDPDev_t* pDev)
\r
210 printf("\n * List of supported pairing method\n");
\r
212 if(!pDev || false == pDev->edp)
\r
214 printf(" Invalid device or Not support direct-pairing..\n\n");
\r
218 if(!pDev->prm || 0 == pDev->prmLen)
\r
220 printf(" Not exist any support method..\n\n");
\r
224 bool bAvailable = true;
\r
225 for(size_t i=0; i<pDev->prmLen; i++)
\r
227 printf(" [%ld] ", i+1);
\r
228 switch (pDev->prm[i])
\r
230 case DP_PRE_CONFIGURED:
\r
231 printf("Pre-Configured PIN");
\r
233 case DP_RANDOM_PIN:
\r
234 printf("Random PIN");
\r
237 printf("NOT Allowed (%d)", pDev->prm[i]);
\r
238 bAvailable = false;
\r
248 // This is a function called back when a device is discovered
\r
249 OCStackApplicationResult discoveryReqCB(void*, OCDoHandle,
\r
250 OCClientResponse * clientResponse)
\r
252 OIC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
\r
254 if (clientResponse)
\r
256 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
257 OIC_LOG_V(INFO, TAG,
\r
258 "Device =============> Discovered @ %s:%d",
\r
259 clientResponse->devAddr.addr,
\r
260 clientResponse->devAddr.port);
\r
262 if (clientResponse->result == OC_STACK_OK)
\r
264 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
268 return OC_STACK_DELETE_TRANSACTION;
\r
272 // This is a function called back when direct-pairing status is changed
\r
273 void pairingReqCB(OCDPDev_t* peer, OCStackResult result)
\r
275 OIC_LOG(INFO, TAG, "Callback Context for Direct-Pairing establishment\n");
\r
277 if (OC_STACK_OK == result)
\r
279 OIC_LOG_V(INFO, TAG,
\r
280 "Direct-Pairing SUCCESS =============> Target @ %s:%d\n",
\r
281 peer->endpoint.addr,
\r
282 peer->endpoint.port);
\r
286 OIC_LOG(ERROR, TAG, "Direct-Pairing FAILED..\n");
\r
290 OCStackApplicationResult getReqCB(void * ctx, OCDoHandle handle, OCClientResponse *clientResponse)
\r
292 OIC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
\r
296 if (clientResponse)
\r
298 OIC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
\r
299 OIC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
\r
300 OIC_LOG_PAYLOAD(INFO, clientResponse->payload);
\r
301 if ((OCSecurityPayload*)clientResponse->payload)
\r
303 OIC_LOG(INFO, TAG, PCF("=============> Get Response"));
\r
306 return OC_STACK_DELETE_TRANSACTION;
\r
309 int DeviceDiscovery()
\r
312 OCCallbackData cbData;
\r
313 char queryUri[200];
\r
314 char ipaddr[100] = { '\0' };
\r
316 snprintf(queryUri, sizeof (queryUri), DISCOVERY_QUERY, ipaddr);
\r
318 cbData.cb = discoveryReqCB;
\r
319 cbData.context = NULL;
\r
322 /* Start a discovery query*/
\r
323 OIC_LOG_V(INFO, TAG, "Resource Discovery : %s\n", queryUri);
\r
325 ret = OCDoResource(NULL, OC_REST_DISCOVER, queryUri, 0, 0, CT_DEFAULT,
\r
326 OC_LOW_QOS, &cbData, NULL, 0);
\r
327 if (ret != OC_STACK_OK)
\r
329 OIC_LOG(ERROR, TAG, "OCStack resource error");
\r
334 OCStackResult DirectPairingDiscovery()
\r
336 // initiate direct pairing discovery
\r
337 OIC_LOG(INFO, TAG, " Discovering Only Owned Devices on Network..");
\r
338 discoveredDevs = OCDiscoverDirectPairingDevices(DP_DISCOVERY_TIMEOUT);
\r
339 if(NULL == discoveredDevs)
\r
341 OIC_LOG(ERROR, TAG, "OCDiscoverDirectPairingDevices API error");
\r
342 return OC_STACK_ERROR;
\r
345 // display the discovered unowned list
\r
346 printf(" > Discovered Direct-Pairing Support Devices\n");
\r
347 printList(discoveredDevs);
\r
349 return OC_STACK_OK;
\r
352 OCStackResult DoDirectPairing(OCDPDev_t* peer, OCPrm_t pmSel, char *pinNumber)
\r
354 if (NULL == peer || NULL == pinNumber)
\r
356 OIC_LOG(ERROR, TAG, "invalid parameter");
\r
357 return OC_STACK_INVALID_PARAM;
\r
360 // start direct pairing
\r
361 OIC_LOG(INFO, TAG, " Start Direct Pairing..");
\r
362 if(OC_STACK_OK != OCDoDirectPairing(peer, pmSel, pinNumber, pairingReqCB))
\r
364 OIC_LOG(ERROR, TAG, "OCDoDirectPairing API error");
\r
365 return OC_STACK_ERROR;
\r
368 return OC_STACK_OK;
\r
371 OCStackResult SendGetRequest(OCDPDev_t* peer)
\r
373 OIC_LOG(INFO, TAG, "Send Get REQ to Led server");
\r
375 char szQueryUri[] = "/a/led";
\r
377 OCCallbackData cbData;
\r
378 OCDevAddr endpoint;
\r
381 memcpy(&endpoint, &peer->endpoint, sizeof(OCDevAddr));
\r
382 endpoint.port = peer->securePort;
\r
383 endpoint.flags = (OCTransportFlags)(endpoint.flags | OC_SECURE);
\r
385 cbData.cb = getReqCB;
\r
386 cbData.context = NULL;
\r
389 OIC_LOG(INFO, TAG, "Request to /a/light ");
\r
390 ret = OCDoResource(&handle, OC_REST_GET, szQueryUri,
\r
391 &endpoint, NULL, peer->connType, OC_LOW_QOS, &cbData, NULL, 0);
\r
392 if (ret != OC_STACK_OK)
\r
394 OIC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, OC_REST_GET);
\r
400 FILE* client_fopen(const char *path, const char *mode)
\r
403 return fopen(CRED_FILE, mode);
\r
406 void *CLInterface(void *data)
\r
408 printf(RED_BEGIN"#Ready to operation ('h' for help)#\n"COLOR_END);
\r
412 char query[MAX_LINE] = {0,};
\r
413 const char prompt[] = BOLD_BEGIN"IoTivity-DP#"COLOR_END" ";
\r
414 const char* helpmsg[6] = {
\r
415 GREEN_BEGIN"# h (or help) : show help message"COLOR_END,
\r
416 GREEN_BEGIN"# dd (DP device discovery) : discover Direct-Pairing devices"COLOR_END,
\r
417 GREEN_BEGIN"# dp (start Direct-Pairing) : negotiate DP method & start Direct-Pairing"COLOR_END,
\r
418 GREEN_BEGIN"# sd (send data) : send data to device"COLOR_END,
\r
419 GREEN_BEGIN"# ll (list all device) : list all discovered/paired devices"COLOR_END,
\r
420 GREEN_BEGIN"# q (quit) : quit test"COLOR_END,
\r
423 for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)
\r
425 fprintf(stderr, "%s\n", helpmsg[i]);
\r
432 const char *input = readline(prompt, NULL);
\r
437 strncpy(query, input, MAX_LINE);
\r
438 if (!strlen(query))
\r
442 else if (!strcmp(query, "h") || !strcmp(query, "help"))
\r
444 for (size_t i=0; i<(sizeof(helpmsg)/sizeof(char*)); i++)
\r
446 fprintf(stderr, "%s\n", helpmsg[i]);
\r
452 if (!strcmp(query, "dd"))
\r
454 OIC_LOG(INFO, TAG, "- Direct-Pairing device discovery -");
\r
456 ret = DirectPairingDiscovery();
\r
457 if (OC_STACK_OK != ret)
\r
459 OIC_LOG(ERROR, TAG, "Error in DirectPairingDiscovery()");
\r
462 else if (!strcmp(query, "dp"))
\r
464 OIC_LOG(INFO, TAG, "- Negotiate DP method & Start Direct-Pairing -");
\r
466 printf("\n * List of discovered device\n");
\r
467 printList(discoveredDevs);
\r
470 OCDPDev_t *peer = NULL;
\r
472 input = readline(" > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);
\r
473 if (!input || !strlen(input))
\r
478 peerIdx = strtol(input, &ptr, 10);
\r
480 peer = getDev(discoveredDevs, (uint32_t)peerIdx);
\r
483 OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");
\r
487 // get pairing method
\r
489 OCPrm_t pmSel = DP_NOT_ALLOWED;
\r
490 if (false == printPairingMethod(peer))
\r
492 OIC_LOG(ERROR, TAG, "Target does not support the Direct-Pairing");
\r
495 input = readline(" > Enter pairing method: ", NULL);
\r
496 if (!input || !strlen(input))
\r
500 pmIdx = strtol(input, &ptr, 10);
\r
502 if (0 >= pmIdx || peer->prmLen+1 < (size_t)pmIdx)
\r
504 OIC_LOG(ERROR, TAG, "Invalid mode selection");
\r
507 pmSel = peer->prm[pmIdx-1];
\r
510 char pinNumber[DP_PIN_LENGTH+1];
\r
511 input = readline(" > Enter PIN Number for authentication (ex - '00000000' [8 digit] ): ", NULL);
\r
512 if (!input || DP_PIN_LENGTH != strlen(input))
\r
514 OIC_LOG(ERROR, TAG, "Invalid PIN");
\r
517 sscanf(input, "%9s", pinNumber);
\r
520 ret = DoDirectPairing(peer, pmSel, pinNumber);
\r
521 if (OC_STACK_OK != ret)
\r
523 OIC_LOG(ERROR, TAG, "Error in DoDirectPairing()");
\r
526 else if (!strcmp(query, "sd"))
\r
528 OIC_LOG(INFO, TAG, "- Send data(GET Request) to device(led server) -");
\r
530 //pairedDevs = OCGetDirectPairedDevices();
\r
531 //printList(pairedDevs);
\r
532 printList(discoveredDevs);
\r
535 OCDPDev_t *peer = NULL;
\r
537 input = readline(" > Enter Peer Device Number to initiate Direct-Pairing: ", NULL);
\r
538 if (!input || !strlen(input))
\r
543 peerIdx = strtol(input, &ptr, 10);
\r
545 //peer = getDev(pairedDevs, peerIdx);
\r
546 peer = getDev(discoveredDevs, (uint32_t)peerIdx);
\r
549 OIC_LOG(ERROR, TAG, "Not found the peer in discovered list");
\r
554 ret = SendGetRequest(peer);
\r
555 if (OC_STACK_OK != ret)
\r
557 OIC_LOG(ERROR, TAG, "Error in SendGetRequest()");
\r
560 else if (!strcmp(query, "ll"))
\r
562 OIC_LOG(INFO, TAG, "- List all discovered and paired devices) -");
\r
564 printf(" > List of discovered devices\n");
\r
565 printList(discoveredDevs);
\r
568 printf(" > List of paired devices\n");
\r
569 pairedDevs = OCGetDirectPairedDevices();
\r
570 printList(pairedDevs);
\r
573 else if (!strcmp(query, "q"))
\r
587 struct timespec timeout;
\r
589 // Initialize Persistent Storage for SVR database
\r
590 OCPersistentStorage ps = { client_fopen, fread, fwrite, fclose, unlink };
\r
591 OCRegisterPersistentStorageHandler(&ps);
\r
593 /* Initialize OCStack*/
\r
594 if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK)
\r
596 OIC_LOG(ERROR, TAG, "OCStack init error");
\r
600 // DeviceDiscovery();
\r
602 timeout.tv_sec = 0;
\r
603 timeout.tv_nsec = 100000000L;
\r
605 // Break from loop with Ctrl+C
\r
606 OIC_LOG(INFO, TAG, "Entering occlient main loop...");
\r
607 signal(SIGINT, handleSigInt);
\r
611 pthread_t p_thread;
\r
612 thr_id = pthread_create(&p_thread, NULL, CLInterface, (void *)NULL);
\r
615 OIC_LOG(ERROR, TAG, "create CLI Thread error");
\r
622 if (OCProcess() != OC_STACK_OK)
\r
624 OIC_LOG(ERROR, TAG, "OCStack process error");
\r
628 nanosleep(&timeout, NULL);
\r
630 OIC_LOG(INFO, TAG, "Exiting occlient main loop...");
\r
632 if (OCStop() != OC_STACK_OK)
\r
634 OIC_LOG(ERROR, TAG, "OCStack stop error");
\r