iodine 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +4 -4
  4. data/SPEC-Websocket-Draft.md +3 -6
  5. data/bin/mustache.rb +128 -0
  6. data/examples/test_template.mustache +16 -0
  7. data/ext/iodine/fio.c +9397 -0
  8. data/ext/iodine/fio.h +4723 -0
  9. data/ext/iodine/fio_ary.h +353 -54
  10. data/ext/iodine/fio_cli.c +351 -361
  11. data/ext/iodine/fio_cli.h +84 -105
  12. data/ext/iodine/fio_hashmap.h +70 -16
  13. data/ext/iodine/fio_json_parser.h +35 -24
  14. data/ext/iodine/fio_siphash.c +104 -4
  15. data/ext/iodine/fio_siphash.h +18 -2
  16. data/ext/iodine/fio_str.h +1218 -0
  17. data/ext/iodine/fio_tmpfile.h +1 -1
  18. data/ext/iodine/fiobj.h +13 -8
  19. data/ext/iodine/fiobj4sock.h +6 -8
  20. data/ext/iodine/fiobj_ary.c +107 -17
  21. data/ext/iodine/fiobj_ary.h +36 -4
  22. data/ext/iodine/fiobj_data.c +146 -127
  23. data/ext/iodine/fiobj_data.h +25 -23
  24. data/ext/iodine/fiobj_hash.c +7 -7
  25. data/ext/iodine/fiobj_hash.h +6 -5
  26. data/ext/iodine/fiobj_json.c +20 -17
  27. data/ext/iodine/fiobj_json.h +5 -5
  28. data/ext/iodine/fiobj_mem.h +71 -0
  29. data/ext/iodine/fiobj_mustache.c +310 -0
  30. data/ext/iodine/fiobj_mustache.h +40 -0
  31. data/ext/iodine/fiobj_numbers.c +199 -94
  32. data/ext/iodine/fiobj_numbers.h +7 -7
  33. data/ext/iodine/fiobj_str.c +142 -333
  34. data/ext/iodine/fiobj_str.h +65 -55
  35. data/ext/iodine/fiobject.c +49 -11
  36. data/ext/iodine/fiobject.h +40 -39
  37. data/ext/iodine/http.c +382 -190
  38. data/ext/iodine/http.h +124 -80
  39. data/ext/iodine/http1.c +99 -127
  40. data/ext/iodine/http1.h +5 -5
  41. data/ext/iodine/http1_parser.c +3 -2
  42. data/ext/iodine/http1_parser.h +2 -2
  43. data/ext/iodine/http_internal.c +14 -12
  44. data/ext/iodine/http_internal.h +25 -19
  45. data/ext/iodine/iodine.c +37 -18
  46. data/ext/iodine/iodine.h +4 -0
  47. data/ext/iodine/iodine_caller.c +9 -2
  48. data/ext/iodine/iodine_caller.h +2 -0
  49. data/ext/iodine/iodine_connection.c +82 -117
  50. data/ext/iodine/iodine_defer.c +57 -50
  51. data/ext/iodine/iodine_defer.h +0 -1
  52. data/ext/iodine/iodine_fiobj2rb.h +4 -2
  53. data/ext/iodine/iodine_helpers.c +4 -4
  54. data/ext/iodine/iodine_http.c +25 -32
  55. data/ext/iodine/iodine_json.c +2 -1
  56. data/ext/iodine/iodine_mustache.c +423 -0
  57. data/ext/iodine/iodine_mustache.h +6 -0
  58. data/ext/iodine/iodine_pubsub.c +48 -153
  59. data/ext/iodine/iodine_pubsub.h +5 -4
  60. data/ext/iodine/iodine_rack_io.c +7 -5
  61. data/ext/iodine/iodine_store.c +16 -13
  62. data/ext/iodine/iodine_tcp.c +26 -34
  63. data/ext/iodine/mustache_parser.h +1085 -0
  64. data/ext/iodine/redis_engine.c +740 -646
  65. data/ext/iodine/redis_engine.h +13 -15
  66. data/ext/iodine/resp_parser.h +11 -5
  67. data/ext/iodine/websocket_parser.h +13 -13
  68. data/ext/iodine/websockets.c +240 -393
  69. data/ext/iodine/websockets.h +52 -113
  70. data/lib/iodine.rb +1 -1
  71. data/lib/iodine/mustache.rb +140 -0
  72. data/lib/iodine/version.rb +1 -1
  73. metadata +15 -28
  74. data/ext/iodine/defer.c +0 -566
  75. data/ext/iodine/defer.h +0 -148
  76. data/ext/iodine/evio.c +0 -26
  77. data/ext/iodine/evio.h +0 -161
  78. data/ext/iodine/evio_callbacks.c +0 -26
  79. data/ext/iodine/evio_epoll.c +0 -251
  80. data/ext/iodine/evio_kqueue.c +0 -194
  81. data/ext/iodine/facil.c +0 -2325
  82. data/ext/iodine/facil.h +0 -616
  83. data/ext/iodine/fio_base64.c +0 -277
  84. data/ext/iodine/fio_base64.h +0 -71
  85. data/ext/iodine/fio_llist.h +0 -257
  86. data/ext/iodine/fio_mem.c +0 -675
  87. data/ext/iodine/fio_mem.h +0 -143
  88. data/ext/iodine/fio_random.c +0 -248
  89. data/ext/iodine/fio_random.h +0 -45
  90. data/ext/iodine/fio_sha1.c +0 -362
  91. data/ext/iodine/fio_sha1.h +0 -107
  92. data/ext/iodine/fio_sha2.c +0 -842
  93. data/ext/iodine/fio_sha2.h +0 -169
  94. data/ext/iodine/pubsub.c +0 -867
  95. data/ext/iodine/pubsub.h +0 -221
  96. data/ext/iodine/sock.c +0 -1366
  97. data/ext/iodine/sock.h +0 -566
  98. data/ext/iodine/spnlock.inc +0 -111
@@ -1,143 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2018
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #ifndef H_FIO_MEM_H
8
-
9
- /**
10
- * This is a custom memory allocator the utilizes memory pools to allow for
11
- * concurrent memory allocations across threads.
12
- *
13
- * Allocated memory is always zeroed out and aligned on a 16 byte boundary.
14
- *
15
- * Reallocated memory is always aligned on a 16 byte boundary but it might be
16
- * filled with junk data after the valid data (this is true also for
17
- * `fio_realloc2`).
18
- *
19
- * The memory allocator assumes multiple concurrent allocation/deallocation,
20
- * short life spans (memory is freed shortly, but not immediately, after it was
21
- * allocated) and we small allocations (realloc almost always copies data).
22
- *
23
- * These assumptions allow the allocator to avoid lock contention by ignoring
24
- * fragmentation within a memory "block" and waiting for the whole "block" to be
25
- * freed before it's memory is recycled (no "free list").
26
- *
27
- * This allocator should NOT be used for objects with a long life-span, because
28
- * even a single persistent object will prevent the re-use of the whole memory
29
- * block (128Kb by default) from which it was allocated.
30
- *
31
- * A memory "block" can include any number of memory pages that are a multiple
32
- * of 2 (up to 1Mb of memory). However, the default value, set by
33
- * MEMORY_BLOCK_SIZE, is either 128Kb (set at th end of this header).
34
- *
35
- * Each block includes a header that uses reference counters and position
36
- * markers.
37
- *
38
- * The position marker (`pos`) marks the next available byte (counted in
39
- * multiples of 16).
40
- *
41
- * The reference counter (`ref`) counts how many pointers reference memory in
42
- * the block (including the "arena" that "owns" the block).
43
- *
44
- * Except for the position marker (`pos`) that acts the same as `sbrk`, there's
45
- * no way to know which "slices" are allocated and which "slices" are available.
46
- *
47
- * Small allocations are differentiated by their memory alignment. If a memory
48
- * allocation is placed 8 bytes after whole block alignment, the memory was
49
- * allocated directly using `mmap` (and it might be using a whole page more than
50
- * request, just because it needed that extra header space!).
51
- *
52
- * The allocator uses `mmap` when requesting memory from the system and for
53
- * allocations bigger than MEMORY_BLOCK_ALLOC_LIMIT (37.5% of the block).
54
- *
55
- * To replace the system's `malloc` function family compile with the
56
- * `FIO_OVERRIDE_MALLOC` defined (`-DFIO_OVERRIDE_MALLOC`).
57
- *
58
- * When using tcmalloc or jemalloc, define `FIO_FORCE_MALLOC` to prevent
59
- * `fio_mem` from compiling (`-DFIO_FORCE_MALLOC`). Function wrappers will be
60
- * compiled just in case, so calls to `fio_malloc` will be routed to `malloc`.
61
- *
62
- */
63
- #define H_FIO_MEM_H
64
-
65
- #include <stdlib.h>
66
-
67
- /** Allocates memory using a per-CPU core block memory pool. */
68
- void *fio_malloc(size_t size);
69
-
70
- /** Allocates memory using a per-CPU core block memory pool. memory is zeroed
71
- * out. */
72
- void *fio_calloc(size_t size, size_t count);
73
-
74
- /** Frees memory that was allocated using this library. */
75
- void fio_free(void *ptr);
76
-
77
- /**
78
- * Re-allocates memory. An attept to avoid copying the data is made only for
79
- * memory allocations larger than 64Kb.
80
- */
81
- void *fio_realloc(void *ptr, size_t new_size);
82
-
83
- /**
84
- * Re-allocates memory. An attept to avoid copying the data is made only for
85
- * memory allocations larger than 64Kb.
86
- *
87
- * This variation is slightly faster as it might copy less data.
88
- */
89
- void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length);
90
-
91
- /** Clears any memory locks, in case of a system call to `fork`. */
92
- void fio_malloc_after_fork(void);
93
-
94
- /** Tests the facil.io memory allocator. */
95
- void fio_malloc_test(void);
96
-
97
- /** If defined, `malloc` will be used instead of the fio_malloc functions */
98
- #if FIO_FORCE_MALLOC
99
- #define fio_malloc malloc
100
- #define fio_calloc calloc
101
- #define fio_free free
102
- #define fio_realloc realloc
103
- #define fio_realloc2(ptr, new_size, old_data_len) realloc((ptr), (new_size))
104
- #define fio_malloc_test()
105
- #define fio_malloc_after_fork
106
-
107
- /* allows local override as well as global override */
108
- #elif FIO_OVERRIDE_MALLOC
109
- #define malloc fio_malloc
110
- #define free fio_free
111
- #define realloc fio_realloc
112
- #define calloc fio_calloc
113
-
114
- #endif
115
-
116
- #ifndef FIO_MEM_MAX_BLOCKS_PER_CORE
117
- /**
118
- * The maximum number of available memory blocks that will be pooled before
119
- * memory is returned to the system.
120
- */
121
- #define FIO_MEM_MAX_BLOCKS_PER_CORE 32 /* approx. 2Mb per CPU core */
122
- #endif
123
-
124
- /** Allocator default settings. */
125
- #ifndef FIO_MEMORY_BLOCK_SIZE_LOG
126
- #define FIO_MEMORY_BLOCK_SIZE_LOG (17) /* 17 == 128Kb */
127
- #endif
128
- #ifndef FIO_MEMORY_BLOCK_SIZE
129
- #define FIO_MEMORY_BLOCK_SIZE ((uintptr_t)1 << FIO_MEMORY_BLOCK_SIZE_LOG)
130
- #endif
131
- #ifndef FIO_MEMORY_BLOCK_MASK
132
- #define FIO_MEMORY_BLOCK_MASK (FIO_MEMORY_BLOCK_SIZE - 1) /* 0b111... */
133
- #endif
134
- #ifndef FIO_MEMORY_BLOCK_SLICES
135
- #define FIO_MEMORY_BLOCK_SLICES (FIO_MEMORY_BLOCK_SIZE >> 4) /* 16B/slice */
136
- #endif
137
- #ifndef FIO_MEMORY_BLOCK_ALLOC_LIMIT
138
- /* defaults to 37.5% of the block */
139
- #define FIO_MEMORY_BLOCK_ALLOC_LIMIT \
140
- ((FIO_MEMORY_BLOCK_SIZE >> 2) + (FIO_MEMORY_BLOCK_SIZE >> 3))
141
- #endif
142
-
143
- #endif /* H_FIO_MEM_H */
@@ -1,248 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2018
3
- License: MIT except for any non-public-domain algorithms (none that I'm aware
4
- of), which might be subject to their own licenses.
5
-
6
- Feel free to copy, use and enjoy in accordance with to the license(s).
7
- */
8
- #ifndef _GNU_SOURCE
9
- #define _GNU_SOURCE
10
- #endif
11
- #include "fio_random.h"
12
-
13
- #include <errno.h>
14
- #include <stdio.h>
15
-
16
- #ifndef __has_include
17
- #define __has_include(x) 0
18
- #endif
19
-
20
- /* include intrinsics if supported */
21
- #if __has_include(<x86intrin.h>)
22
- #include <x86intrin.h>
23
- #define HAVE_X86Intrin
24
- /*
25
- see: https://software.intel.com/en-us/node/513411
26
- and: https://software.intel.com/sites/landingpage/IntrinsicsGuide/
27
- */
28
- #endif /* __has_include(<x86intrin.h>) */
29
-
30
- /* check for unix support */
31
- #if defined(__unix__) || defined(__linux__) || defined(__APPLE__) || \
32
- (__has_include(<unistd.h>) && __has_include(<pthread.h>))
33
- #ifndef HAS_UNIX_FEATURES
34
- #define HAS_UNIX_FEATURES
35
- #endif
36
- #endif
37
-
38
- // clang-format off
39
- #if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
40
- # if defined(__has_include)
41
- # if __has_include(<endian.h>)
42
- # include <endian.h>
43
- # elif __has_include(<sys/endian.h>)
44
- # include <sys/endian.h>
45
- # endif
46
- # endif
47
- # if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
48
- __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
49
- # define __BIG_ENDIAN__
50
- # endif
51
- #endif
52
- // clang-format on
53
-
54
- #if defined(USE_ALT_RANDOM) || !defined(HAS_UNIX_FEATURES)
55
- #include "fio_sha2.h"
56
- #include <time.h>
57
- #include <string.h>
58
-
59
- static inline void fio_random_data(sha2_s *sha2) {
60
- #ifdef RUSAGE_SELF
61
- struct rusage rusage;
62
- getrusage(RUSAGE_SELF, &rusage);
63
- fio_sha2_write(sha2, &rusage, sizeof(rusage));
64
- #elif defined CLOCKS_PER_SEC
65
- size_t clk = (size_t)clock();
66
- fio_sha2_write(&sha2, &clk, sizeof(clk));
67
- time_t the_time;
68
- time(&the_time);
69
- fio_sha2_write(sha2, &the_time, sizeof(the_time));
70
- fio_sha2_write(sha2, &fio_rand64, sizeof(void *));
71
- fio_sha2_write(sha2, &fio_rand_bytes, sizeof(void *));
72
- {
73
- char junk_data[64];
74
- fio_sha2_write(sha2, junk_data, 64);
75
- }
76
- #else
77
- #error Random alternative failed to find access to the CPU clock state.
78
- #endif
79
- fio_sha2_write(sha2, sha2, sizeof(void *));
80
- }
81
-
82
- uint32_t fio_rand32(void) {
83
- sha2_s sha2 = fio_sha2_init(SHA_512);
84
- fio_random_data(&sha2);
85
- fio_sha2_result(&sha2);
86
- return *((uint32_t *)sha2.buffer);
87
- }
88
-
89
- uint64_t fio_rand64(void) {
90
- sha2_s sha2 = fio_sha2_init(SHA_512);
91
- fio_random_data(&sha2);
92
- fio_sha2_result(&sha2);
93
- return *((uint64_t *)sha2.buffer);
94
- }
95
-
96
- void fio_rand_bytes(void *target, size_t length) {
97
- sha2_s sha2 = fio_sha2_init(SHA_512);
98
- fio_random_data(&sha2);
99
- fio_sha2_result(&sha2);
100
-
101
- while (length >= 64) {
102
- memcpy(target, sha2.digest.str, 64);
103
- length -= 64;
104
- target = (void *)((uintptr_t)target + 64);
105
- fio_random_data(&sha2);
106
- fio_sha2_result(&sha2);
107
- }
108
- if (length >= 32) {
109
- memcpy(target, sha2.digest.str, 32);
110
- length -= 32;
111
- target = (void *)((uintptr_t)target + 32);
112
- fio_random_data(&sha2);
113
- fio_sha2_result(&sha2);
114
- }
115
- if (length >= 16) {
116
- memcpy(target, sha2.digest.str, 16);
117
- length -= 16;
118
- target = (void *)((uintptr_t)target + 16);
119
- fio_random_data(&sha2);
120
- fio_sha2_result(&sha2);
121
- }
122
- if (length >= 8) {
123
- memcpy(target, sha2.digest.str, 8);
124
- length -= 8;
125
- target = (void *)((uintptr_t)target + 8);
126
- fio_random_data(&sha2);
127
- fio_sha2_result(&sha2);
128
- }
129
- while (length) {
130
- *((uint8_t *)target) = sha2.digest.str[length];
131
- target = (void *)((uintptr_t)target + 1);
132
- --length;
133
- }
134
- }
135
-
136
- #else
137
- /* ***************************************************************************
138
- Unix Random Engine (use built in machine)
139
- */
140
- #include <errno.h>
141
- #include <fcntl.h>
142
- #include <pthread.h>
143
- #include <unistd.h>
144
-
145
- /* ***************************************************************************
146
- Machine specific changes
147
- */
148
- // #ifdef __linux__
149
- // #undef bswap16
150
- // #undef bswap32
151
- // #undef bswap64
152
- // #include <machine/bswap.h>
153
- // #endif
154
- #ifdef HAVE_X86Intrin
155
- // #undef bswap16
156
- /*
157
- #undef bswap32
158
- #define bswap32(i) \
159
- { __asm__("bswap %k0" : "+r"(i) :); }
160
- */
161
- #undef bswap64
162
- #define bswap64(i) \
163
- { __asm__("bswapq %0" : "+r"(i) :); }
164
-
165
- // shadow sched_yield as _mm_pause for spinwait
166
- #define sched_yield() _mm_pause()
167
- #endif
168
-
169
- /* ***************************************************************************
170
- Random fd
171
- ***************************************************************************** */
172
-
173
- /* rand generator management */
174
- static int fio_rand_fd_ = -1;
175
- static void close_rand_fd(void) {
176
- if (fio_rand_fd_ >= 0)
177
- close(fio_rand_fd_);
178
- fio_rand_fd_ = -1;
179
- }
180
- static void init_rand_fd(void) {
181
- if (fio_rand_fd_ < 0) {
182
- while ((fio_rand_fd_ = open("/dev/urandom", O_RDONLY)) == -1) {
183
- if (errno == ENXIO) {
184
- perror("FATAL ERROR: caanot initiate random generator");
185
- exit(-1);
186
- }
187
- sched_yield();
188
- }
189
- }
190
- atexit(close_rand_fd);
191
- }
192
-
193
- /* ***************************************************************************
194
- Random API ... (why is this not a system call?)
195
- ***************************************************************************** */
196
-
197
- /* rand function template */
198
- #define MAKE_RAND_FUNC(type, func_name) \
199
- type func_name(void) { \
200
- if (fio_rand_fd_ < 0) \
201
- init_rand_fd(); \
202
- type ret; \
203
- while (read(fio_rand_fd_, &ret, sizeof(type)) < 0) \
204
- sched_yield(); \
205
- return ret; \
206
- }
207
- /* rand functions */
208
- MAKE_RAND_FUNC(uint32_t, fio_rand32)
209
- MAKE_RAND_FUNC(uint64_t, fio_rand64)
210
- /* clear template */
211
- #undef MAKE_RAND_FUNC
212
-
213
- void fio_rand_bytes(void *target, size_t length) {
214
- if (fio_rand_fd_ < 0)
215
- init_rand_fd();
216
- while (read(fio_rand_fd_, target, length) < 0)
217
- sched_yield();
218
- }
219
- #endif /* Unix Random */
220
-
221
- /*******************************************************************************
222
- Random Testing
223
- ***************************************************************************** */
224
- #if DEBUG
225
- void fio_random_test(void) {
226
- uint64_t buffer[8];
227
- clock_t start, end;
228
- fio_rand64();
229
- start = clock();
230
- for (size_t i = 0; i < 100000; i++) {
231
- buffer[i & 7] = fio_rand64();
232
- }
233
- end = clock();
234
- fprintf(stderr,
235
- "+ Random generator available\n+ created 100K X 64bits "
236
- "Random %lu CPU clock count\n",
237
- end - start);
238
- start = clock();
239
- for (size_t i = 0; i < 100000; i++) {
240
- fio_rand_bytes(buffer, 64);
241
- }
242
- end = clock();
243
- fprintf(stderr,
244
- "+ created 100K X 512bits "
245
- "Random %lu CPU clock count\n",
246
- end - start);
247
- }
248
- #endif
@@ -1,45 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2017
3
- License: MIT except for any non-public-domain algorithms (none that I'm aware
4
- of), which might be subject to their own licenses.
5
-
6
- Feel free to copy, use and enjoy in accordance with to the license(s).
7
- */
8
- #ifndef fio_RANDOM_H
9
- #define fio_RANDOM_H
10
- /* *****************************************************************************
11
- C++ extern
12
- */
13
-
14
- #include <stdint.h>
15
- #include <stdlib.h>
16
-
17
- #if defined(__cplusplus)
18
- extern "C" {
19
- #endif
20
-
21
- /* ***************************************************************************
22
- Random stuff... (why is this not a system call?)
23
- */
24
-
25
- /** returns 32 random bits. */
26
- uint32_t fio_rand32(void);
27
-
28
- /** returns 64 random bits. */
29
- uint64_t fio_rand64(void);
30
-
31
- /** returns a variable length string of random bytes. */
32
- void fio_rand_bytes(void *target, size_t length);
33
-
34
- #if DEBUG
35
- void fio_random_test(void);
36
- #endif
37
-
38
- /* *****************************************************************************
39
- C++ extern finish
40
- */
41
- #if defined(__cplusplus)
42
- }
43
- #endif
44
-
45
- #endif
@@ -1,362 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2017
3
- License: MIT except for any non-public-domain algorithms (none that I'm aware
4
- of), which might be subject to their own licenses.
5
-
6
- Feel free to copy, use and enjoy in accordance with to the license(s).
7
- */
8
- #ifndef _GNU_SOURCE
9
- #define _GNU_SOURCE
10
- #endif
11
- #include "fio_sha1.h"
12
-
13
- #include <string.h>
14
-
15
- /*****************************************************************************
16
- Useful Macros - Not all of them are used here, but it's a copy-paste convenience
17
- */
18
-
19
- /** 32Bit left rotation, inlined. */
20
- #define left_rotate32(i, bits) \
21
- (((uint32_t)(i) << (bits)) | ((uint32_t)(i) >> (32 - (bits))))
22
- /** 32Bit right rotation, inlined. */
23
- #define right_rotate32(i, bits) \
24
- (((uint32_t)(i) >> (bits)) | ((uint32_t)(i) << (32 - (bits))))
25
- /** 64Bit left rotation, inlined. */
26
- #define left_rotate64(i, bits) \
27
- (((uint64_t)(i) << (bits)) | ((uint64_t)(i) >> (64 - (bits))))
28
- /** 64Bit right rotation, inlined. */
29
- #define right_rotate64(i, bits) \
30
- (((uint64_t)(i) >> (bits)) | ((uint64_t)(i) << (64 - (bits))))
31
- /** unknown size element - left rotation, inlined. */
32
- #define left_rotate(i, bits) (((i) << (bits)) | ((i) >> (sizeof((i)) - (bits))))
33
- /** unknown size element - right rotation, inlined. */
34
- #define right_rotate(i, bits) \
35
- (((i) >> (bits)) | ((i) << (sizeof((i)) - (bits))))
36
- /** inplace byte swap 16 bit integer */
37
- #define bswap16(i) \
38
- do { \
39
- (i) = (((i)&0xFFU) << 8) | (((i)&0xFF00U) >> 8); \
40
- } while (0);
41
- /** inplace byte swap 32 bit integer */
42
- #define bswap32(i) \
43
- do { \
44
- (i) = (((i)&0xFFUL) << 24) | (((i)&0xFF00UL) << 8) | \
45
- (((i)&0xFF0000UL) >> 8) | (((i)&0xFF000000UL) >> 24); \
46
- } while (0);
47
- /** inplace byte swap 64 bit integer */
48
- #define bswap64(i) \
49
- do { \
50
- (i) = (((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) | \
51
- (((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) | \
52
- (((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) | \
53
- (((i)&0xFF000000000000ULL) >> 40) | \
54
- (((i)&0xFF00000000000000ULL) >> 56); \
55
- } while (0);
56
-
57
- static const uint8_t sha1_padding[64] = {0x80, 0};
58
-
59
- #ifdef __BIG_ENDIAN__
60
- /** Converts a 4 byte string to a uint32_t word. careful with alignment! */
61
- #define str2word(c) (*((uint32_t *)(c)))
62
- #else
63
- /**
64
- Converts a 4 byte string to a Big Endian uint32_t word. (ignores alignment!)
65
- */
66
- #define str2word(c) \
67
- (((*((uint32_t *)(c))) & 0xFFUL) << 24) | \
68
- (((*((uint32_t *)(c))) & 0xFF00UL) << 8) | \
69
- (((*((uint32_t *)(c))) & 0xFF0000UL) >> 8) | \
70
- (((*((uint32_t *)(c))) & 0xFF000000UL) >> 24)
71
- #endif
72
- /**
73
- Process the buffer once full.
74
- */
75
- static inline void perform_all_rounds(sha1_s *s, const uint8_t *buffer) {
76
- /* collect data */
77
- uint32_t a = s->digest.i[0];
78
- uint32_t b = s->digest.i[1];
79
- uint32_t c = s->digest.i[2];
80
- uint32_t d = s->digest.i[3];
81
- uint32_t e = s->digest.i[4];
82
- uint32_t t, w[16];
83
- /* copy data to words, performing byte swapping as needed */
84
- w[0] = str2word(buffer);
85
- w[1] = str2word(buffer + 4);
86
- w[2] = str2word(buffer + 8);
87
- w[3] = str2word(buffer + 12);
88
- w[4] = str2word(buffer + 16);
89
- w[5] = str2word(buffer + 20);
90
- w[6] = str2word(buffer + 24);
91
- w[7] = str2word(buffer + 28);
92
- w[8] = str2word(buffer + 32);
93
- w[9] = str2word(buffer + 36);
94
- w[10] = str2word(buffer + 40);
95
- w[11] = str2word(buffer + 44);
96
- w[12] = str2word(buffer + 48);
97
- w[13] = str2word(buffer + 52);
98
- w[14] = str2word(buffer + 56);
99
- w[15] = str2word(buffer + 60);
100
- /* perform rounds */
101
- #define perform_single_round(num) \
102
- t = left_rotate32(a, 5) + e + w[num] + ((b & c) | ((~b) & d)) + 0x5A827999; \
103
- e = d; \
104
- d = c; \
105
- c = left_rotate32(b, 30); \
106
- b = a; \
107
- a = t;
108
-
109
- #define perform_four_rounds(i) \
110
- perform_single_round(i); \
111
- perform_single_round(i + 1); \
112
- perform_single_round(i + 2); \
113
- perform_single_round(i + 3);
114
-
115
- perform_four_rounds(0);
116
- perform_four_rounds(4);
117
- perform_four_rounds(8);
118
- perform_four_rounds(12);
119
-
120
- #undef perform_single_round
121
- #define perform_single_round(i) \
122
- w[(i)&15] = left_rotate32((w[(i - 3) & 15] ^ w[(i - 8) & 15] ^ \
123
- w[(i - 14) & 15] ^ w[(i - 16) & 15]), \
124
- 1); \
125
- t = left_rotate32(a, 5) + e + w[(i)&15] + ((b & c) | ((~b) & d)) + \
126
- 0x5A827999; \
127
- e = d; \
128
- d = c; \
129
- c = left_rotate32(b, 30); \
130
- b = a; \
131
- a = t;
132
-
133
- perform_four_rounds(16);
134
-
135
- #undef perform_single_round
136
- #define perform_single_round(i) \
137
- w[(i)&15] = left_rotate32((w[(i - 3) & 15] ^ w[(i - 8) & 15] ^ \
138
- w[(i - 14) & 15] ^ w[(i - 16) & 15]), \
139
- 1); \
140
- t = left_rotate32(a, 5) + e + w[(i)&15] + (b ^ c ^ d) + 0x6ED9EBA1; \
141
- e = d; \
142
- d = c; \
143
- c = left_rotate32(b, 30); \
144
- b = a; \
145
- a = t;
146
-
147
- perform_four_rounds(20);
148
- perform_four_rounds(24);
149
- perform_four_rounds(28);
150
- perform_four_rounds(32);
151
- perform_four_rounds(36);
152
-
153
- #undef perform_single_round
154
- #define perform_single_round(i) \
155
- w[(i)&15] = left_rotate32((w[(i - 3) & 15] ^ w[(i - 8) & 15] ^ \
156
- w[(i - 14) & 15] ^ w[(i - 16) & 15]), \
157
- 1); \
158
- t = left_rotate32(a, 5) + e + w[(i)&15] + ((b & (c | d)) | (c & d)) + \
159
- 0x8F1BBCDC; \
160
- e = d; \
161
- d = c; \
162
- c = left_rotate32(b, 30); \
163
- b = a; \
164
- a = t;
165
-
166
- perform_four_rounds(40);
167
- perform_four_rounds(44);
168
- perform_four_rounds(48);
169
- perform_four_rounds(52);
170
- perform_four_rounds(56);
171
- #undef perform_single_round
172
- #define perform_single_round(i) \
173
- w[(i)&15] = left_rotate32((w[(i - 3) & 15] ^ w[(i - 8) & 15] ^ \
174
- w[(i - 14) & 15] ^ w[(i - 16) & 15]), \
175
- 1); \
176
- t = left_rotate32(a, 5) + e + w[(i)&15] + (b ^ c ^ d) + 0xCA62C1D6; \
177
- e = d; \
178
- d = c; \
179
- c = left_rotate32(b, 30); \
180
- b = a; \
181
- a = t;
182
- perform_four_rounds(60);
183
- perform_four_rounds(64);
184
- perform_four_rounds(68);
185
- perform_four_rounds(72);
186
- perform_four_rounds(76);
187
-
188
- /* store data */
189
- s->digest.i[4] += e;
190
- s->digest.i[3] += d;
191
- s->digest.i[2] += c;
192
- s->digest.i[1] += b;
193
- s->digest.i[0] += a;
194
- }
195
-
196
- /* ***************************************************************************
197
- SHA-1 hashing
198
- */
199
-
200
- /**
201
- Initialize or reset the `sha1` object. This must be performed before hashing
202
- data using sha1.
203
- */
204
- sha1_s fio_sha1_init(void) {
205
- return (sha1_s){.digest.i[0] = 0x67452301,
206
- .digest.i[1] = 0xefcdab89,
207
- .digest.i[2] = 0x98badcfe,
208
- .digest.i[3] = 0x10325476,
209
- .digest.i[4] = 0xc3d2e1f0};
210
- }
211
-
212
- /**
213
- Writes data to the sha1 buffer.
214
- */
215
- void fio_sha1_write(sha1_s *s, const void *data, size_t len) {
216
- size_t in_buffer = s->length & 63;
217
- size_t partial = 64 - in_buffer;
218
- s->length += len;
219
- if (partial > len) {
220
- memcpy(s->buffer + in_buffer, data, len);
221
- return;
222
- }
223
- if (in_buffer) {
224
- memcpy(s->buffer + in_buffer, data, partial);
225
- len -= partial;
226
- data = (void *)((uintptr_t)data + partial);
227
- perform_all_rounds(s, s->buffer);
228
- }
229
- while (len >= 64) {
230
- perform_all_rounds(s, data);
231
- data = (void *)((uintptr_t)data + 64);
232
- len -= 64;
233
- }
234
- if (len) {
235
- memcpy(s->buffer + in_buffer, data, len);
236
- }
237
- return;
238
- }
239
-
240
- char *fio_sha1_result(sha1_s *s) {
241
- size_t in_buffer = s->length & 63;
242
- if (in_buffer > 55) {
243
- memcpy(s->buffer + in_buffer, sha1_padding, 64 - in_buffer);
244
- perform_all_rounds(s, s->buffer);
245
- memcpy(s->buffer, sha1_padding + 1, 56);
246
- } else if (in_buffer != 55) {
247
- memcpy(s->buffer + in_buffer, sha1_padding, 56 - in_buffer);
248
- } else {
249
- s->buffer[55] = sha1_padding[0];
250
- }
251
- /* store the length in BITS - alignment should be promised by struct */
252
- /* this must the number in BITS, encoded as a BIG ENDIAN 64 bit number */
253
- uint64_t *len = (uint64_t *)(s->buffer + 56);
254
- *len = s->length << 3;
255
- #ifndef __BIG_ENDIAN__
256
- bswap64(*len);
257
- #endif
258
- perform_all_rounds(s, s->buffer);
259
-
260
- /* change back to little endian, if required */
261
- #ifndef __BIG_ENDIAN__
262
- bswap32(s->digest.i[0]);
263
- bswap32(s->digest.i[1]);
264
- bswap32(s->digest.i[2]);
265
- bswap32(s->digest.i[3]);
266
- bswap32(s->digest.i[4]);
267
- #endif
268
- // fprintf(stderr, "result requested, in hex, is:");
269
- // for (size_t i = 0; i < 20; i++)
270
- // fprintf(stderr, "%02x", (unsigned int)(s->digest.str[i] & 0xFF));
271
- // fprintf(stderr, "\r\n");
272
- return (char *)s->digest.str;
273
- }
274
-
275
- /*******************************************************************************
276
- SHA-1 testing
277
- */
278
- #if defined(DEBUG) && DEBUG == 1
279
- #include <stdio.h>
280
- #include <time.h>
281
-
282
- // clang-format off
283
- #if defined(HAVE_OPENSSL)
284
- # include <openssl/sha.h>
285
- #endif
286
- // clang-format on
287
-
288
- void fio_sha1_test(void) {
289
- struct {
290
- char *str;
291
- uint8_t hash[21];
292
- } sets[] = {
293
- {"The quick brown fox jumps over the lazy dog",
294
- {0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84, 0x9e,
295
- 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12, 0}}, // a set with
296
- // a string
297
- {"",
298
- {
299
- 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
300
- 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09,
301
- }}, // an empty set
302
- {NULL, {0}} // Stop
303
- };
304
- int i = 0;
305
- sha1_s sha1;
306
- fprintf(stderr, "===================================\n");
307
- fprintf(stderr, "fio SHA-1 struct size: %zu\n", sizeof(sha1_s));
308
- fprintf(stderr, "+ fio");
309
- while (sets[i].str) {
310
- sha1 = fio_sha1_init();
311
- fio_sha1_write(&sha1, sets[i].str, strlen(sets[i].str));
312
- if (strcmp(fio_sha1_result(&sha1), (char *)sets[i].hash)) {
313
- fprintf(stderr, ":\n--- fio SHA-1 Test FAILED!\nstring: %s\nexpected: ",
314
- sets[i].str);
315
- char *p = (char *)sets[i].hash;
316
- while (*p)
317
- fprintf(stderr, "%02x", *(p++) & 0xFF);
318
- fprintf(stderr, "\ngot: ");
319
- p = fio_sha1_result(&sha1);
320
- while (*p)
321
- fprintf(stderr, "%02x", *(p++) & 0xFF);
322
- fprintf(stderr, "\n");
323
- return;
324
- }
325
- i++;
326
- }
327
- fprintf(stderr, " SHA-1 passed.\n");
328
-
329
- #ifdef HAVE_OPENSSL
330
- fprintf(stderr, "===================================\n");
331
- fprintf(stderr, "fio SHA-1 struct size: %lu\n",
332
- (unsigned long)sizeof(sha1_s));
333
- fprintf(stderr, "OpenSSL SHA-1 struct size: %lu\n",
334
- (unsigned long)sizeof(SHA_CTX));
335
- fprintf(stderr, "===================================\n");
336
-
337
- unsigned char hash[SHA512_DIGEST_LENGTH + 1];
338
- hash[SHA512_DIGEST_LENGTH] = 0;
339
- clock_t start;
340
- start = clock();
341
- for (i = 0; i < 100000; i++) {
342
- sha1 = fio_sha1_init();
343
- fio_sha1_write(&sha1, "The quick brown fox jumps over the lazy dog ", 43);
344
- fio_sha1_result(&sha1);
345
- }
346
- fprintf(stderr, "fio 100K SHA-1: %lf\n",
347
- (double)(clock() - start) / CLOCKS_PER_SEC);
348
-
349
- hash[SHA_DIGEST_LENGTH] = 0;
350
- SHA_CTX o_sh1;
351
- start = clock();
352
- for (i = 0; i < 100000; i++) {
353
- SHA1_Init(&o_sh1);
354
- SHA1_Update(&o_sh1, "The quick brown fox jumps over the lazy dog", 43);
355
- SHA1_Final(hash, &o_sh1);
356
- }
357
- fprintf(stderr, "OpenSSL 100K SHA-1: %lf\n",
358
- (double)(clock() - start) / CLOCKS_PER_SEC);
359
-
360
- #endif
361
- }
362
- #endif