iodine 0.4.19 → 0.5.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- data/ext/iodine/xor-crypt.h +0 -107
data/ext/iodine/random.c
DELETED
@@ -1,208 +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 "random.h"
|
12
|
-
|
13
|
-
#if defined(USE_ALT_RANDOM) || !defined(HAS_UNIX_FEATURES)
|
14
|
-
#include "sha2.h"
|
15
|
-
#include <time.h>
|
16
|
-
|
17
|
-
#ifdef RUSAGE_SELF
|
18
|
-
static size_t get_clock_mili(void) {
|
19
|
-
struct rusage rusage;
|
20
|
-
getrusage(RUSAGE_SELF, &rusage);
|
21
|
-
return ((rusage.ru_utime.tv_sec + rusage.ru_stime.tv_sec) * 1000000) +
|
22
|
-
(rusage.ru_utime.tv_usec + rusage.ru_stime.tv_usec);
|
23
|
-
}
|
24
|
-
#elif defined CLOCKS_PER_SEC
|
25
|
-
#define get_clock_mili() (size_t) clock()
|
26
|
-
#else
|
27
|
-
#define get_clock_mili() 0
|
28
|
-
#error Random alternative failed to find access to the CPU clock state.
|
29
|
-
#endif
|
30
|
-
|
31
|
-
uint32_t bscrypt_rand32(void) {
|
32
|
-
bits256_u pseudo = bscrypt_rand256();
|
33
|
-
return pseudo.ints[3];
|
34
|
-
}
|
35
|
-
|
36
|
-
uint64_t bscrypt_rand64(void) {
|
37
|
-
bits256_u pseudo = bscrypt_rand256();
|
38
|
-
return pseudo.words[3];
|
39
|
-
}
|
40
|
-
|
41
|
-
bits128_u bscrypt_rand128(void) {
|
42
|
-
bits256_u pseudo = bscrypt_rand256();
|
43
|
-
bits128_u ret;
|
44
|
-
ret.words[0] = pseudo.words[0];
|
45
|
-
ret.words[1] = pseudo.words[1];
|
46
|
-
return ret;
|
47
|
-
}
|
48
|
-
|
49
|
-
bits256_u bscrypt_rand256(void) {
|
50
|
-
size_t cpu_state = get_clock_mili();
|
51
|
-
time_t the_time;
|
52
|
-
time(&the_time);
|
53
|
-
bits256_u pseudo;
|
54
|
-
sha2_s sha2 = bscrypt_sha2_init(SHA_256);
|
55
|
-
bscrypt_sha2_write(&sha2, &cpu_state, sizeof(cpu_state));
|
56
|
-
bscrypt_sha2_write(&sha2, &the_time, sizeof(the_time));
|
57
|
-
bscrypt_sha2_write(&sha2, ((char *)&cpu_state) - 64, 64); /* the stack */
|
58
|
-
bscrypt_sha2_result(&sha2);
|
59
|
-
pseudo.words[0] = sha2.digest.i64[0];
|
60
|
-
pseudo.words[1] = sha2.digest.i64[1];
|
61
|
-
pseudo.words[2] = sha2.digest.i64[2];
|
62
|
-
pseudo.words[3] = sha2.digest.i64[3];
|
63
|
-
return pseudo;
|
64
|
-
}
|
65
|
-
|
66
|
-
void bscrypt_rand_bytes(void *target, size_t length) {
|
67
|
-
clock_t cpu_state = clock();
|
68
|
-
time_t the_time;
|
69
|
-
time(&the_time);
|
70
|
-
sha2_s sha2 = bscrypt_sha2_init(SHA_512);
|
71
|
-
bscrypt_sha2_write(&sha2, &cpu_state, sizeof(cpu_state));
|
72
|
-
bscrypt_sha2_write(&sha2, &the_time, sizeof(the_time));
|
73
|
-
bscrypt_sha2_write(&sha2, &cpu_state - 2, 64); /* whatever's on the stack */
|
74
|
-
bscrypt_sha2_result(&sha2);
|
75
|
-
while (length > 64) {
|
76
|
-
memcpy(target, sha2.digest.str, 64);
|
77
|
-
length -= 64;
|
78
|
-
target = (void *)((uintptr_t)target + 64);
|
79
|
-
bscrypt_sha2_write(&sha2, &cpu_state, sizeof(cpu_state));
|
80
|
-
bscrypt_sha2_result(&sha2);
|
81
|
-
}
|
82
|
-
if (length > 32) {
|
83
|
-
memcpy(target, sha2.digest.str, 32);
|
84
|
-
length -= 32;
|
85
|
-
target = (void *)((uintptr_t)target + 32);
|
86
|
-
bscrypt_sha2_write(&sha2, &cpu_state, sizeof(cpu_state));
|
87
|
-
bscrypt_sha2_result(&sha2);
|
88
|
-
}
|
89
|
-
if (length > 16) {
|
90
|
-
memcpy(target, sha2.digest.str, 16);
|
91
|
-
length -= 16;
|
92
|
-
target = (void *)((uintptr_t)target + 16);
|
93
|
-
bscrypt_sha2_write(&sha2, &cpu_state, sizeof(cpu_state));
|
94
|
-
bscrypt_sha2_result(&sha2);
|
95
|
-
}
|
96
|
-
if (length > 8) {
|
97
|
-
memcpy(target, sha2.digest.str, 8);
|
98
|
-
length -= 8;
|
99
|
-
target = (void *)((uintptr_t)target + 8);
|
100
|
-
bscrypt_sha2_write(&sha2, &cpu_state, sizeof(cpu_state));
|
101
|
-
bscrypt_sha2_result(&sha2);
|
102
|
-
}
|
103
|
-
while (length) {
|
104
|
-
*((uint8_t *)target) = sha2.digest.str[length];
|
105
|
-
target = (void *)((uintptr_t)target + 1);
|
106
|
-
--length;
|
107
|
-
}
|
108
|
-
}
|
109
|
-
|
110
|
-
#else
|
111
|
-
/* ***************************************************************************
|
112
|
-
Unix Random Engine (use built in machine)
|
113
|
-
*/
|
114
|
-
#include <errno.h>
|
115
|
-
#include <fcntl.h>
|
116
|
-
#include <pthread.h>
|
117
|
-
#include <unistd.h>
|
118
|
-
|
119
|
-
/* ***************************************************************************
|
120
|
-
Machine specific changes
|
121
|
-
*/
|
122
|
-
// #ifdef __linux__
|
123
|
-
// #undef bswap16
|
124
|
-
// #undef bswap32
|
125
|
-
// #undef bswap64
|
126
|
-
// #include <machine/bswap.h>
|
127
|
-
// #endif
|
128
|
-
#ifdef HAVE_X86Intrin
|
129
|
-
// #undef bswap16
|
130
|
-
/*
|
131
|
-
#undef bswap32
|
132
|
-
#define bswap32(i) \
|
133
|
-
{ __asm__("bswap %k0" : "+r"(i) :); }
|
134
|
-
*/
|
135
|
-
#undef bswap64
|
136
|
-
#define bswap64(i) \
|
137
|
-
{ __asm__("bswapq %0" : "+r"(i) :); }
|
138
|
-
|
139
|
-
// shadow sched_yield as _mm_pause for spinwait
|
140
|
-
#define sched_yield() _mm_pause()
|
141
|
-
#endif
|
142
|
-
|
143
|
-
/* ***************************************************************************
|
144
|
-
Random ... (why is this not a system call?)
|
145
|
-
*/
|
146
|
-
|
147
|
-
/* rand generator management */
|
148
|
-
static int _rand_fd_ = -1;
|
149
|
-
static void close_rand_fd(void) {
|
150
|
-
if (_rand_fd_ >= 0)
|
151
|
-
close(_rand_fd_);
|
152
|
-
_rand_fd_ = -1;
|
153
|
-
}
|
154
|
-
static void init_rand_fd(void) {
|
155
|
-
if (_rand_fd_ < 0) {
|
156
|
-
while ((_rand_fd_ = open("/dev/urandom", O_RDONLY)) == -1) {
|
157
|
-
if (errno == ENXIO)
|
158
|
-
perror("bscrypt fatal error, caanot initiate random generator"),
|
159
|
-
exit(-1);
|
160
|
-
sched_yield();
|
161
|
-
}
|
162
|
-
}
|
163
|
-
atexit(close_rand_fd);
|
164
|
-
}
|
165
|
-
/* rand function template */
|
166
|
-
#define MAKE_RAND_FUNC(type, func_name) \
|
167
|
-
type func_name(void) { \
|
168
|
-
if (_rand_fd_ < 0) \
|
169
|
-
init_rand_fd(); \
|
170
|
-
type ret; \
|
171
|
-
while (read(_rand_fd_, &ret, sizeof(type)) < 0) \
|
172
|
-
sched_yield(); \
|
173
|
-
return ret; \
|
174
|
-
}
|
175
|
-
/* rand functions */
|
176
|
-
MAKE_RAND_FUNC(uint32_t, bscrypt_rand32)
|
177
|
-
MAKE_RAND_FUNC(uint64_t, bscrypt_rand64)
|
178
|
-
MAKE_RAND_FUNC(bits128_u, bscrypt_rand128)
|
179
|
-
MAKE_RAND_FUNC(bits256_u, bscrypt_rand256)
|
180
|
-
/* clear template */
|
181
|
-
#undef MAKE_RAND_FUNC
|
182
|
-
|
183
|
-
void bscrypt_rand_bytes(void *target, size_t length) {
|
184
|
-
if (_rand_fd_ < 0)
|
185
|
-
init_rand_fd();
|
186
|
-
while (read(_rand_fd_, target, length) < 0)
|
187
|
-
sched_yield();
|
188
|
-
}
|
189
|
-
#endif /* Unix Random */
|
190
|
-
|
191
|
-
/*******************************************************************************
|
192
|
-
Random
|
193
|
-
*/
|
194
|
-
#if defined(DEBUG) && DEBUG == 1
|
195
|
-
void bscrypt_test_random(void) {
|
196
|
-
clock_t start, end;
|
197
|
-
bscrypt_rand256();
|
198
|
-
start = clock();
|
199
|
-
for (size_t i = 0; i < 100000; i++) {
|
200
|
-
bscrypt_rand256();
|
201
|
-
}
|
202
|
-
end = clock();
|
203
|
-
fprintf(stderr,
|
204
|
-
"+ bscrypt Random generator available\n+ bscrypt 100K X 256bit "
|
205
|
-
"Random %lu CPU clock count\n",
|
206
|
-
end - start);
|
207
|
-
}
|
208
|
-
#endif
|
@@ -1,278 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 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
|
-
#include "spnlock.inc"
|
9
|
-
|
10
|
-
#include "fio_list.h"
|
11
|
-
#include "redis_connection.h"
|
12
|
-
#include <errno.h>
|
13
|
-
#include <math.h>
|
14
|
-
#include <signal.h>
|
15
|
-
#include <string.h>
|
16
|
-
#include <strings.h>
|
17
|
-
|
18
|
-
/* *****************************************************************************
|
19
|
-
Memory and Data structures - The protocol object.
|
20
|
-
***************************************************************************** */
|
21
|
-
#ifndef REDIS_POOL_SIZES /* per protocol */
|
22
|
-
#define REDIS_POOL_SIZES 256
|
23
|
-
#endif
|
24
|
-
|
25
|
-
#ifndef REDIS_READ_BUFFER /* during network data events */
|
26
|
-
#define REDIS_READ_BUFFER 2048
|
27
|
-
#endif
|
28
|
-
|
29
|
-
/* a protocol ID string */
|
30
|
-
static const char *REDIS_PROTOCOL_ID =
|
31
|
-
"Redis Protocol for the facil.io framework";
|
32
|
-
/* Pings */
|
33
|
-
#define REDIS_PING_LEN 24
|
34
|
-
static const char REDIS_PING_STR[] = "*2\r\n"
|
35
|
-
"$4\r\nPING\r\n"
|
36
|
-
"$24\r\nfacil.io connection PING\r\n";
|
37
|
-
static const char REDIS_PING_PAYLOAD[] = "facil.io connection PING";
|
38
|
-
|
39
|
-
typedef struct {
|
40
|
-
protocol_s protocol;
|
41
|
-
struct redis_context_args *settings;
|
42
|
-
unsigned authenticated : 1;
|
43
|
-
} redis_protocol_s;
|
44
|
-
|
45
|
-
static inline size_t ul2a(char *dest, size_t num) {
|
46
|
-
uint8_t digits = 1;
|
47
|
-
size_t tmp = num;
|
48
|
-
while ((tmp /= 10))
|
49
|
-
++digits;
|
50
|
-
|
51
|
-
if (dest) {
|
52
|
-
dest += digits;
|
53
|
-
*(dest--) = 0;
|
54
|
-
}
|
55
|
-
for (size_t i = 0; i < digits; i++) {
|
56
|
-
num = num - (10 * (tmp = (num / 10)));
|
57
|
-
if (dest)
|
58
|
-
*(dest--) = '0' + num;
|
59
|
-
num = tmp;
|
60
|
-
}
|
61
|
-
return digits;
|
62
|
-
}
|
63
|
-
|
64
|
-
/* *****************************************************************************
|
65
|
-
The Protocol Context
|
66
|
-
***************************************************************************** */
|
67
|
-
#undef redis_create_context
|
68
|
-
void *redis_create_context(struct redis_context_args args) {
|
69
|
-
if (!args.on_message || !args.parser) {
|
70
|
-
fprintf(stderr, "A Redix connection context requires both an `on_message` "
|
71
|
-
"callback and a parser.\n");
|
72
|
-
exit(EINVAL);
|
73
|
-
}
|
74
|
-
if (args.auth) {
|
75
|
-
if (!args.auth_len)
|
76
|
-
args.auth_len = strlen(args.auth);
|
77
|
-
args.auth_len++;
|
78
|
-
}
|
79
|
-
struct redis_context_args *c = malloc(sizeof(*c) + args.auth_len);
|
80
|
-
*c = args;
|
81
|
-
if (args.auth) {
|
82
|
-
c->auth_len--;
|
83
|
-
c->auth = (char *)(c + 1);
|
84
|
-
memcpy(c->auth, args.auth, c->auth_len);
|
85
|
-
c->auth[c->auth_len] = 0;
|
86
|
-
}
|
87
|
-
return c;
|
88
|
-
}
|
89
|
-
|
90
|
-
/* *****************************************************************************
|
91
|
-
The Protocol Callbacks
|
92
|
-
***************************************************************************** */
|
93
|
-
|
94
|
-
void redis_protocol_cleanup(intptr_t uuid, void *settings) {
|
95
|
-
struct redis_context_args *s = settings;
|
96
|
-
if (s->on_close)
|
97
|
-
s->on_close(uuid, s->udata);
|
98
|
-
if (s->autodestruct)
|
99
|
-
free(settings);
|
100
|
-
}
|
101
|
-
|
102
|
-
static void redis_on_close_client(intptr_t uuid, protocol_s *pr) {
|
103
|
-
redis_protocol_s *r = (redis_protocol_s *)pr;
|
104
|
-
// if (r->settings->on_close)
|
105
|
-
// r->settings->on_close(uuid, r->settings->udata);
|
106
|
-
redis_protocol_cleanup(uuid, r->settings);
|
107
|
-
free(r);
|
108
|
-
}
|
109
|
-
|
110
|
-
static void redis_on_close_server(intptr_t uuid, protocol_s *pr) {
|
111
|
-
redis_protocol_s *r = (redis_protocol_s *)pr;
|
112
|
-
if (r->settings->on_close)
|
113
|
-
r->settings->on_close(uuid, r->settings->udata);
|
114
|
-
free(r);
|
115
|
-
}
|
116
|
-
|
117
|
-
/** called when a connection's timeout was reached */
|
118
|
-
static void redis_ping(intptr_t uuid, protocol_s *pr) {
|
119
|
-
/* We cannow write directly to the socket in case `redis_send` has scheduled
|
120
|
-
* callbacks. */
|
121
|
-
sock_write2(.uuid = uuid, .buffer = REDIS_PING_STR,
|
122
|
-
.length = sizeof(REDIS_PING_STR) - 1, .move = 1,
|
123
|
-
.dealloc = SOCK_DEALLOC_NOOP);
|
124
|
-
(void)pr;
|
125
|
-
}
|
126
|
-
|
127
|
-
/** called when a data is available, but will not run concurrently */
|
128
|
-
static void redis_on_data_deferred(intptr_t uuid, protocol_s *pr, void *d);
|
129
|
-
static void redis_on_data(intptr_t uuid, protocol_s *pr) {
|
130
|
-
redis_protocol_s *r = (redis_protocol_s *)pr;
|
131
|
-
uint8_t buffer[REDIS_READ_BUFFER];
|
132
|
-
ssize_t len, limit, pos;
|
133
|
-
resp_object_s *msg;
|
134
|
-
limit = len = sock_read(uuid, buffer, REDIS_READ_BUFFER);
|
135
|
-
if (len <= 0)
|
136
|
-
return;
|
137
|
-
pos = 0;
|
138
|
-
while (len) {
|
139
|
-
msg = resp_parser_feed(r->settings->parser, buffer + pos, (size_t *)&len);
|
140
|
-
if (!len && !msg) {
|
141
|
-
fprintf(stderr, "ERROR: (RESP Parser) Bad input (%lu):\n%s\n", limit,
|
142
|
-
buffer);
|
143
|
-
/* we'll simply ignore bad input. skip a line. */
|
144
|
-
for (; pos < limit; pos++) {
|
145
|
-
len++;
|
146
|
-
if (buffer[pos] == '\n') {
|
147
|
-
pos++;
|
148
|
-
len++;
|
149
|
-
break; /* from `for` loop */
|
150
|
-
}
|
151
|
-
}
|
152
|
-
continue; /* while loop */
|
153
|
-
}
|
154
|
-
if (msg) {
|
155
|
-
if (r->authenticated) {
|
156
|
-
r->authenticated--;
|
157
|
-
if (msg->type != RESP_OK) {
|
158
|
-
if (msg->type == RESP_ERR) {
|
159
|
-
fprintf(stderr,
|
160
|
-
"ERROR: (RedisConnection) Authentication FAILED.\n"
|
161
|
-
" %s\n",
|
162
|
-
resp_obj2str(msg)->string);
|
163
|
-
} else {
|
164
|
-
fprintf(stderr,
|
165
|
-
"ERROR: (RedisConnection) Authentication FAILED "
|
166
|
-
"(unexpected response %d).\n",
|
167
|
-
msg->type);
|
168
|
-
}
|
169
|
-
}
|
170
|
-
} else if ((msg->type == RESP_STRING &&
|
171
|
-
resp_obj2str(msg)->len == REDIS_PING_LEN &&
|
172
|
-
!memcmp(resp_obj2str(msg)->string, REDIS_PING_PAYLOAD,
|
173
|
-
REDIS_PING_LEN)) ||
|
174
|
-
(msg->type == RESP_ARRAY &&
|
175
|
-
resp_obj2arr(msg)->array[0]->type == RESP_STRING &&
|
176
|
-
resp_obj2str(resp_obj2arr(msg)->array[0])->len == 4 &&
|
177
|
-
resp_obj2arr(msg)->array[1]->type == RESP_STRING &&
|
178
|
-
resp_obj2str(resp_obj2arr(msg)->array[1])->len ==
|
179
|
-
REDIS_PING_LEN &&
|
180
|
-
!strncasecmp(
|
181
|
-
(char *)resp_obj2str(resp_obj2arr(msg)->array[0])->string,
|
182
|
-
"pong", 4) &&
|
183
|
-
!memcmp(
|
184
|
-
(char *)resp_obj2str(resp_obj2arr(msg)->array[0])->string,
|
185
|
-
REDIS_PING_PAYLOAD, REDIS_PING_LEN))) {
|
186
|
-
/* an internal ping, do not forward. */
|
187
|
-
} else
|
188
|
-
r->settings->on_message(uuid, msg, r->settings->udata);
|
189
|
-
resp_free_object(msg);
|
190
|
-
msg = NULL;
|
191
|
-
}
|
192
|
-
if (len == limit) {
|
193
|
-
/* fragment events, it's edge polling, so we need to read everything */
|
194
|
-
facil_defer(.uuid = uuid, .task = redis_on_data_deferred,
|
195
|
-
.task_type = FIO_PR_LOCK_TASK);
|
196
|
-
return;
|
197
|
-
}
|
198
|
-
pos += len;
|
199
|
-
limit = len = limit - len;
|
200
|
-
}
|
201
|
-
}
|
202
|
-
static void redis_on_data_deferred(intptr_t uuid, protocol_s *pr, void *d) {
|
203
|
-
if (!pr || pr->service != REDIS_PROTOCOL_ID)
|
204
|
-
return;
|
205
|
-
redis_on_data(uuid, pr);
|
206
|
-
(void)d;
|
207
|
-
}
|
208
|
-
|
209
|
-
static void redis_on_open(intptr_t uuid, protocol_s *pr, void *d) {
|
210
|
-
redis_protocol_s *r = (void *)pr;
|
211
|
-
facil_set_timeout(uuid, r->settings->ping);
|
212
|
-
if (r->settings->auth) {
|
213
|
-
r->authenticated = 1;
|
214
|
-
size_t n_len = ul2a(NULL, r->settings->auth_len);
|
215
|
-
char *t =
|
216
|
-
malloc(r->settings->auth_len + 20 + n_len); /* 19 is probably enough */
|
217
|
-
memcpy(t, "*2\r\n$4\r\nAUTH\r\n$", 15);
|
218
|
-
ul2a(t + 15, r->settings->auth_len);
|
219
|
-
t[15 + n_len] = '\r';
|
220
|
-
t[16 + n_len] = '\n';
|
221
|
-
memcpy(t + 17 + n_len, r->settings->auth, r->settings->auth_len);
|
222
|
-
t[17 + n_len + r->settings->auth_len] = '\r';
|
223
|
-
t[18 + n_len + r->settings->auth_len] = '\n';
|
224
|
-
t[19 + n_len + r->settings->auth_len] = 0; /* we don't need it, but nice */
|
225
|
-
sock_write2(.uuid = uuid, .buffer = t,
|
226
|
-
.length = (19 + n_len + r->settings->auth_len), .move = 1);
|
227
|
-
|
228
|
-
} else
|
229
|
-
r->authenticated = 0;
|
230
|
-
r->settings->on_open(uuid, r->settings->udata);
|
231
|
-
(void)d;
|
232
|
-
}
|
233
|
-
|
234
|
-
/**
|
235
|
-
* This function is used as a function pointer for the `facil_connect` and
|
236
|
-
* calls (the `on_connect` callback).
|
237
|
-
*/
|
238
|
-
protocol_s *redis_create_client_protocol(intptr_t uuid, void *settings) {
|
239
|
-
redis_protocol_s *r = malloc(sizeof(*r));
|
240
|
-
*r = (redis_protocol_s){
|
241
|
-
.protocol =
|
242
|
-
{
|
243
|
-
.service = REDIS_PROTOCOL_ID,
|
244
|
-
.on_data = redis_on_data,
|
245
|
-
.on_close = redis_on_close_client,
|
246
|
-
.ping = redis_ping,
|
247
|
-
},
|
248
|
-
.settings = settings,
|
249
|
-
};
|
250
|
-
facil_set_timeout(uuid, r->settings->ping);
|
251
|
-
if (r->settings->on_open)
|
252
|
-
facil_defer(.task = redis_on_open, .uuid = uuid);
|
253
|
-
return &r->protocol;
|
254
|
-
(void)uuid;
|
255
|
-
}
|
256
|
-
|
257
|
-
/**
|
258
|
-
* This function is used as a function pointer for the `facil_listen` calls (the
|
259
|
-
* `on_open` callbacks).
|
260
|
-
*/
|
261
|
-
protocol_s *redis_create_server_protocol(intptr_t uuid, void *settings) {
|
262
|
-
redis_protocol_s *r = malloc(sizeof(*r));
|
263
|
-
*r = (redis_protocol_s){
|
264
|
-
.protocol =
|
265
|
-
{
|
266
|
-
.service = REDIS_PROTOCOL_ID,
|
267
|
-
.on_data = redis_on_data,
|
268
|
-
.on_close = redis_on_close_server,
|
269
|
-
.ping = redis_ping,
|
270
|
-
},
|
271
|
-
.settings = settings,
|
272
|
-
};
|
273
|
-
facil_set_timeout(uuid, r->settings->ping);
|
274
|
-
if (r->settings->on_open)
|
275
|
-
facil_defer(.task = redis_on_open, .uuid = uuid);
|
276
|
-
return &r->protocol;
|
277
|
-
(void)uuid;
|
278
|
-
}
|