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