Undo revert "Generate iotivity_config.h at build time"
[platform/upstream/iotivity.git] / resource / c_common / ocrandom / src / ocrandom.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH 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 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
25 //
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
29 #ifndef _POSIX_C_SOURCE
30 #define _POSIX_C_SOURCE 200809L
31 #endif
32
33 #include "iotivity_config.h"
34
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #ifdef HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47 #ifdef HAVE_TIME_H
48 #include <time.h>
49 #endif
50 #if defined(__ANDROID__)
51 #include <ctype.h>
52 #include <linux/time.h>
53 #endif
54 #ifdef HAVE_WINDOWS_H
55 #include <windows.h>
56 #endif
57 #include "ocrandom.h"
58 #include <stdio.h>
59
60 #ifdef HAVE_UUID_UUID_H
61 #include <uuid/uuid.h>
62 #endif
63
64 #define NANO_SEC 1000000000
65
66 #ifdef ARDUINO
67 #include "Arduino.h"
68
69 // ARM GCC compiler doesnt define srandom function.
70 #if defined(ARDUINO) && !defined(ARDUINO_ARCH_SAM)
71 #define HAVE_SRANDOM 1
72 #endif
73
74 uint8_t GetRandomBitRaw()
75 {
76     return analogRead((uint8_t)ANALOG_IN) & 0x1;
77 }
78
79 uint8_t GetRandomBitRaw2()
80 {
81     int a = 0;
82     for (;;)
83     {
84         a = GetRandomBitRaw() | (GetRandomBitRaw()<<1);
85         if (a==1)
86         {
87             return 0; // 1 to 0 transition: log a zero bit
88         }
89         if (a==2)
90         {
91             return 1;// 0 to 1 transition: log a one bit
92         }
93         // For other cases, try again.
94     }
95 }
96
97 uint8_t GetRandomBit()
98 {
99     int a = 0;
100     for (;;)
101     {
102         a = GetRandomBitRaw2() | (GetRandomBitRaw2()<<1);
103         if (a==1)
104         {
105             return 0; // 1 to 0 transition: log a zero bit
106         }
107         if (a==2)
108         {
109             return 1;// 0 to 1 transition: log a one bit
110         }
111         // For other cases, try again.
112     }
113 }
114 #endif
115
116 int8_t OCSeedRandom()
117 {
118 #ifndef ARDUINO
119     // Get current time to Seed.
120     uint64_t currentTime = 0;
121 #ifdef __ANDROID__
122     struct timespec getTs;
123     clock_gettime(CLOCK_MONOTONIC, &getTs);
124     currentTime = (getTs.tv_sec * (uint64_t)NANO_SEC + getTs.tv_nsec)/1000;
125 #elif _WIN32
126     LARGE_INTEGER count;
127     if (QueryPerformanceCounter(&count)) {
128         currentTime = count.QuadPart;
129     }
130 #elif  _POSIX_TIMERS > 0
131     struct timespec ts;
132     clock_gettime(CLOCK_MONOTONIC, &ts);
133     currentTime = (ts.tv_sec * (uint64_t)NANO_SEC + ts.tv_nsec)/ 1000;
134 #else
135     struct timeval tv;
136     gettimeofday(&tv, NULL);
137     currentTime = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec;
138 #endif
139 #if defined(__unix__) || defined(__APPLE__)
140     int32_t fd = open("/dev/urandom", O_RDONLY);
141     if (fd >= 0)
142     {
143         uint32_t randomSeed = 0;
144         uint32_t totalRead = 0; //how many integers were read
145         int32_t currentRead = 0;
146         while (totalRead < sizeof(randomSeed))
147         {
148             currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
149                     sizeof(randomSeed) - totalRead);
150             if (currentRead > 0)
151             {
152                 totalRead += currentRead;
153             }
154         }
155         close(fd);
156         srand(randomSeed | currentTime);
157     }
158     else
159 #endif
160     {
161         // Do time based seed when problem in accessing "/dev/urandom"
162         srand(currentTime);
163     }
164
165     return 0;
166 #elif defined ARDUINO
167     uint32_t result =0;
168     uint8_t i;
169     for (i=32; i--;)
170     {
171         result += result + GetRandomBit();
172     }
173 #if HAVE_SRANDOM
174     srandom(result);
175 #else
176     srand(result);
177 #endif
178     return 0;
179 #endif
180
181 }
182
183 void OCFillRandomMem(uint8_t * location, uint16_t len)
184 {
185     if (!location)
186     {
187         return;
188     }
189     for (; len--;)
190     {
191         *location++ = OCGetRandomByte();
192     }
193 }
194
195 uint32_t OCGetRandom()
196 {
197     uint32_t result = 0;
198     OCFillRandomMem((uint8_t*) &result, 4);
199     return result;
200 }
201
202 uint8_t OCGetRandomByte(void)
203 {
204 #ifdef HAVE_SRANDOM
205     return random() & 0x00FF;
206 #else
207     return rand() & 0x00FF;
208 #endif
209 }
210
211 uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
212 {
213     uint32_t base;
214     uint32_t diff;
215     uint32_t result;
216     if (firstBound > secondBound)
217     {
218         base = secondBound;
219         diff = firstBound - secondBound;
220     }
221     else if (firstBound < secondBound)
222     {
223         base = firstBound;
224         diff = secondBound - firstBound;
225     }
226     else
227     {
228         return secondBound;
229     }
230     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
231     return result;
232 }
233
234 #if defined(__ANDROID__)
235 uint8_t parseUuidChar(char c)
236 {
237     if (isdigit(c))
238     {
239         return c - '0';
240     }
241     else
242     {
243         return c - 'a' + 10;
244     }
245 }
246 uint8_t parseUuidPart(const char *c)
247 {
248     return (parseUuidChar(c[0])<<4) + parseUuidChar(c[1]);
249 }
250 #endif
251
252 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
253 {
254     if (!uuid)
255     {
256         return RAND_UUID_INVALID_PARAM;
257     }
258 #if defined(__ANDROID__)
259     char uuidString[UUID_STRING_SIZE];
260     int8_t ret = OCGenerateUuidString(uuidString);
261
262     if (ret < 0)
263     {
264         return ret;
265     }
266
267     uuid[ 0] = parseUuidPart(&uuidString[0]);
268     uuid[ 1] = parseUuidPart(&uuidString[2]);
269     uuid[ 2] = parseUuidPart(&uuidString[4]);
270     uuid[ 3] = parseUuidPart(&uuidString[6]);
271
272     uuid[ 4] = parseUuidPart(&uuidString[9]);
273     uuid[ 5] = parseUuidPart(&uuidString[11]);
274
275     uuid[ 6] = parseUuidPart(&uuidString[14]);
276     uuid[ 7] = parseUuidPart(&uuidString[16]);
277
278     uuid[ 8] = parseUuidPart(&uuidString[19]);
279     uuid[ 9] = parseUuidPart(&uuidString[21]);
280
281     uuid[10] = parseUuidPart(&uuidString[24]);
282     uuid[11] = parseUuidPart(&uuidString[26]);
283     uuid[12] = parseUuidPart(&uuidString[28]);
284     uuid[13] = parseUuidPart(&uuidString[30]);
285     uuid[14] = parseUuidPart(&uuidString[32]);
286     uuid[15] = parseUuidPart(&uuidString[34]);
287
288     return RAND_UUID_OK;
289 #elif defined(HAVE_UUID_UUID_H)
290     // note: uuid_t is typedefed as unsigned char[16] on linux/apple
291     uuid_generate(uuid);
292     return RAND_UUID_OK;
293 #else
294     // Fallback for all platforms is filling the array with random data
295     OCFillRandomMem(uuid, UUID_SIZE);
296     return RAND_UUID_OK;
297 #endif
298 }
299
300 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
301 {
302     if (!uuidString)
303     {
304         return RAND_UUID_INVALID_PARAM;
305     }
306 #if defined(__ANDROID__)
307     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
308     if (fd > 0)
309     {
310         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
311         close(fd);
312         if (readResult < 0)
313         {
314             return RAND_UUID_READ_ERROR;
315         }
316         else if (readResult < UUID_STRING_SIZE - 1)
317         {
318             uuidString[0] = '\0';
319             return RAND_UUID_READ_ERROR;
320         }
321
322         uuidString[UUID_STRING_SIZE - 1] = '\0';
323         for (char* p = uuidString; *p; ++p)
324         {
325             *p = tolower(*p);
326         }
327         return RAND_UUID_OK;
328     }
329     else
330     {
331         close(fd);
332         return RAND_UUID_READ_ERROR;
333     }
334 #elif defined(HAVE_UUID_UUID_H)
335     uint8_t uuid[UUID_SIZE];
336     int8_t ret = OCGenerateUuid(uuid);
337
338     if (ret != 0)
339     {
340         return ret;
341     }
342
343     uuid_unparse_lower(uuid, uuidString);
344     return RAND_UUID_OK;
345
346 #else
347     uint8_t uuid[UUID_SIZE];
348     OCGenerateUuid(uuid);
349
350     return OCConvertUuidToString(uuid, uuidString);
351 #endif
352 }
353
354 OCRandomUuidResult OCConvertUuidToString(const uint8_t uuid[UUID_SIZE],
355                                          char uuidString[UUID_STRING_SIZE])
356 {
357     if (uuid == NULL || uuidString == NULL)
358     {
359         return RAND_UUID_INVALID_PARAM;
360     }
361
362
363     int ret = snprintf(uuidString, UUID_STRING_SIZE,
364             "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
365             uuid[0], uuid[1], uuid[2], uuid[3],
366             uuid[4], uuid[5], uuid[6], uuid[7],
367             uuid[8], uuid[9], uuid[10], uuid[11],
368             uuid[12], uuid[13], uuid[14], uuid[15]
369             );
370
371     if (ret != UUID_STRING_SIZE - 1)
372     {
373         return RAND_UUID_CONVERT_ERROR;
374     }
375
376     return RAND_UUID_OK;
377 }