iodine 0.4.19 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/bscrypt.h
DELETED
|
@@ -1,49 +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 BSCRYPT
|
|
9
|
-
/**
|
|
10
|
-
The bscrypt library supplies some **basic** cryptographic functions.
|
|
11
|
-
|
|
12
|
-
Read the README file for more details.
|
|
13
|
-
|
|
14
|
-
All functions will be available using the prefix `bscrypt_`, i.e.:
|
|
15
|
-
|
|
16
|
-
char buffer[13] = {0};
|
|
17
|
-
bscrypt_base64_encode(buffer, "My String", 9);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*/
|
|
21
|
-
#define BSCRYPT "0.0.1"
|
|
22
|
-
|
|
23
|
-
#include "base64.h"
|
|
24
|
-
#include "bscrypt-common.h"
|
|
25
|
-
#include "hex.h"
|
|
26
|
-
#include "misc.h"
|
|
27
|
-
#include "random.h"
|
|
28
|
-
#include "sha1.h"
|
|
29
|
-
#include "sha2.h"
|
|
30
|
-
#include "siphash.h"
|
|
31
|
-
#include "xor-crypt.h"
|
|
32
|
-
|
|
33
|
-
#if defined(DEBUG) && DEBUG == 1
|
|
34
|
-
#define bscrypt_test() \
|
|
35
|
-
{ \
|
|
36
|
-
bscrypt_test_sha1(); \
|
|
37
|
-
bscrypt_test_sha2(); \
|
|
38
|
-
bscrypt_test_base64(); \
|
|
39
|
-
bscrypt_test_random(); \
|
|
40
|
-
bscrypt_test_siphash(); \
|
|
41
|
-
}
|
|
42
|
-
#else
|
|
43
|
-
#define bscrypt_test() \
|
|
44
|
-
fprintf(stderr, \
|
|
45
|
-
"Debug mode not enabled, define DEBUG as 1 in the compiler.\n");
|
|
46
|
-
#endif
|
|
47
|
-
|
|
48
|
-
/* end include gate */
|
|
49
|
-
#endif
|
data/ext/iodine/fio2resp.c
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright: Boaz Segev, 2017
|
|
3
|
-
License: MIT
|
|
4
|
-
|
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
|
6
|
-
|
|
7
|
-
Copyright refers to the parser, not the protocol.
|
|
8
|
-
*/
|
|
9
|
-
#ifndef _GNU_SOURCE
|
|
10
|
-
#define _GNU_SOURCE
|
|
11
|
-
#endif
|
|
12
|
-
|
|
13
|
-
#include "fiobj.h"
|
|
14
|
-
#include "resp.h"
|
|
15
|
-
|
|
16
|
-
#include <stdio.h>
|
|
17
|
-
#include <stdlib.h>
|
|
18
|
-
#include <string.h>
|
|
19
|
-
|
|
20
|
-
static int resp_fioformat_task(fiobj_s *obj, void *s_) {
|
|
21
|
-
fiobj_s *str = s_;
|
|
22
|
-
|
|
23
|
-
if (obj->type == FIOBJ_T_FALSE)
|
|
24
|
-
fiobj_str_write(str, "false\r\n", 7);
|
|
25
|
-
else if (obj->type == FIOBJ_T_TRUE)
|
|
26
|
-
fiobj_str_write(str, "true\r\n", 6);
|
|
27
|
-
else if (obj->type == FIOBJ_T_NULL)
|
|
28
|
-
fiobj_str_write(str, "$-1\r\n", 4);
|
|
29
|
-
else if (obj->type == FIOBJ_T_ARRAY)
|
|
30
|
-
fiobj_str_write2(str, "*%lu\r\n", (unsigned long)fiobj_ary_count(obj));
|
|
31
|
-
else if (obj->type == FIOBJ_T_HASH)
|
|
32
|
-
fiobj_str_write2(str, "*%lu\r\n", (unsigned long)fiobj_hash_count(obj));
|
|
33
|
-
else if (obj->type == FIOBJ_T_COUPLET) {
|
|
34
|
-
fiobj_str_write(str, "*2\r\n", 4);
|
|
35
|
-
resp_fioformat_task(fiobj_couplet2key(obj), s_);
|
|
36
|
-
resp_fioformat_task(fiobj_couplet2obj(obj), s_);
|
|
37
|
-
} else {
|
|
38
|
-
if (obj->type == FIOBJ_T_SYMBOL || FIOBJ_IS_STRING(obj)) {
|
|
39
|
-
/* use this opportunity to optimize memory allocation to page boundries */
|
|
40
|
-
fio_cstr_s s = fiobj_obj2cstr(str);
|
|
41
|
-
if (fiobj_str_capa(str) <= s.len + 128 + fiobj_obj2cstr(obj).len) {
|
|
42
|
-
fiobj_str_resize(str, (((fiobj_str_capa(str) >> 12) + 1) << 12) - 1);
|
|
43
|
-
fiobj_str_resize(str, s.len);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
fiobj_str_join(str, obj);
|
|
47
|
-
fiobj_str_write(str, "\r\n", 2);
|
|
48
|
-
}
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
#undef safe_write_eol
|
|
52
|
-
#undef safe_write1
|
|
53
|
-
#undef safe_write2
|
|
54
|
-
#undef safe_write_i
|
|
55
|
-
|
|
56
|
-
fiobj_pt resp_fioformat(fiobj_pt obj) {
|
|
57
|
-
fiobj_pt str = fiobj_str_buf(4096);
|
|
58
|
-
fiobj_each2(obj, resp_fioformat_task, str);
|
|
59
|
-
return str;
|
|
60
|
-
}
|
data/ext/iodine/fio2resp.h
DELETED
|
@@ -1,51 +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
|
-
#ifndef H_FIO2RESP_FORMAT_H
|
|
9
|
-
/**
|
|
10
|
-
This is a neive implementation of the RESP protocol for Redis.
|
|
11
|
-
*/
|
|
12
|
-
#define H_FIO2RESP_FORMAT_H
|
|
13
|
-
|
|
14
|
-
#include "fiobj.h"
|
|
15
|
-
#include "resp.h"
|
|
16
|
-
|
|
17
|
-
/* support C++ */
|
|
18
|
-
#ifdef __cplusplus
|
|
19
|
-
extern "C" {
|
|
20
|
-
#endif
|
|
21
|
-
|
|
22
|
-
/* *****************************************************************************
|
|
23
|
-
`fiobj_s` => RESP (formatting): implemented seperately; can be safely removed.
|
|
24
|
-
***************************************************************************** */
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Returns a **new** String object containing a RESP representation of `obj`.
|
|
28
|
-
*
|
|
29
|
-
* Returns NULL on failur.
|
|
30
|
-
*
|
|
31
|
-
* Obviously, RESP objects and `fiobj_s` objects aren't fully compatible,
|
|
32
|
-
* meaning that the RESP_OK and RESP_ERR aren't implemented.
|
|
33
|
-
*
|
|
34
|
-
* Also, `FIOBJ_T_HASH` objects are rendered as a flattened Array of `[key,
|
|
35
|
-
* value, key, value, ...]`, any `FIOBJ_T_FLOAT` will be converted to an Integet
|
|
36
|
-
* (the decimal information discarded) and any other object is converted to a
|
|
37
|
-
* String. `FIOBJ_T_IO` and `FIOBJ_T_FILE` are ignored.
|
|
38
|
-
*
|
|
39
|
-
* No `parser` argument is provided and extensions aren't supported for this
|
|
40
|
-
* format.
|
|
41
|
-
*
|
|
42
|
-
* To write a RESP OK or Error don;t use this function. Instead, simply ctreate
|
|
43
|
-
* a new String "OK" or "-error message".
|
|
44
|
-
*/
|
|
45
|
-
fiobj_pt resp_fioformat(fiobj_pt obj);
|
|
46
|
-
|
|
47
|
-
#ifdef __cplusplus
|
|
48
|
-
} /* extern "C" */
|
|
49
|
-
#endif
|
|
50
|
-
|
|
51
|
-
#endif
|
data/ext/iodine/fio_dict.c
DELETED
|
@@ -1,446 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright: Boaz segev, 2017
|
|
3
|
-
License: MIT
|
|
4
|
-
|
|
5
|
-
Feel free to copy, use and enjoy according to the license provided.
|
|
6
|
-
*/
|
|
7
|
-
#include "fio_dict.h"
|
|
8
|
-
/**
|
|
9
|
-
`fio_dict_s` Is based on a 4-bit trie structure, allowing for fast no-collisions
|
|
10
|
-
key-value matching while avoiding any hashing.
|
|
11
|
-
|
|
12
|
-
It's memory intensive... very memory intensive... but it has 0 collision risk
|
|
13
|
-
and offers fairly high performance.
|
|
14
|
-
|
|
15
|
-
Just to offer some insight, a single key-value pair for the key "hello" will
|
|
16
|
-
require ~1,360 bytes. Add the key "bye!" ad you'll add ~1,088 bytes more... but
|
|
17
|
-
the key "hello1" will cost only 272 bytes... brrr.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/* *****************************************************************************
|
|
21
|
-
Inline variation
|
|
22
|
-
***************************************************************************** */
|
|
23
|
-
|
|
24
|
-
static inline fio_dict_s *fio_dict_step_inline(fio_dict_s *dict,
|
|
25
|
-
uint8_t prefix) {
|
|
26
|
-
if (!dict)
|
|
27
|
-
return NULL;
|
|
28
|
-
dict = dict->trie[prefix & 0xf];
|
|
29
|
-
if (!dict)
|
|
30
|
-
return NULL;
|
|
31
|
-
return dict->trie[(prefix >> 4) & 0xf];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
static inline fio_dict_s *fio_dict_prefix_inline(fio_dict_s *dict,
|
|
35
|
-
void *prefix_, size_t len) {
|
|
36
|
-
uint8_t *prefix = prefix_;
|
|
37
|
-
while (dict && len) {
|
|
38
|
-
dict = fio_dict_step_inline(dict, *prefix);
|
|
39
|
-
prefix++;
|
|
40
|
-
len--;
|
|
41
|
-
}
|
|
42
|
-
if (len)
|
|
43
|
-
return NULL;
|
|
44
|
-
return dict;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/* *****************************************************************************
|
|
48
|
-
Implementation
|
|
49
|
-
***************************************************************************** */
|
|
50
|
-
|
|
51
|
-
/** Returns the `fio_dict_s *` object associated with the key, NULL if none.
|
|
52
|
-
*/
|
|
53
|
-
fio_dict_s *fio_dict_get(fio_dict_s *dict, void *key, size_t key_len) {
|
|
54
|
-
dict = fio_dict_prefix_inline(dict, key, key_len);
|
|
55
|
-
if (dict && dict->used)
|
|
56
|
-
return dict;
|
|
57
|
-
return NULL;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Returns the old `fio_dict_s *` object associated with the key, if any.*/
|
|
61
|
-
fio_dict_s *fio_dict_set(fio_dict_s *dict, void *key, size_t key_len,
|
|
62
|
-
fio_dict_s *node) {
|
|
63
|
-
uint8_t *pos = key;
|
|
64
|
-
uint8_t tr;
|
|
65
|
-
fio_dict_s *old;
|
|
66
|
-
if (!key_len || !dict)
|
|
67
|
-
return NULL;
|
|
68
|
-
if (!node) {
|
|
69
|
-
dict = fio_dict_get(dict, key, key_len);
|
|
70
|
-
fio_dict_remove(dict);
|
|
71
|
-
return dict;
|
|
72
|
-
}
|
|
73
|
-
if (key_len > 1) {
|
|
74
|
-
pos += key_len - 1;
|
|
75
|
-
dict = fio_dict_ensure_prefix(dict, key, key_len - 1);
|
|
76
|
-
}
|
|
77
|
-
tr = *pos & 0xf;
|
|
78
|
-
if (!dict->trie[tr]) {
|
|
79
|
-
if (node == NULL)
|
|
80
|
-
return NULL;
|
|
81
|
-
dict->trie[tr] = malloc(sizeof(fio_dict_s));
|
|
82
|
-
*dict->trie[tr] = (fio_dict_s){.trie_val = tr, .parent = dict};
|
|
83
|
-
}
|
|
84
|
-
dict = dict->trie[tr];
|
|
85
|
-
|
|
86
|
-
tr = ((*pos) >> 4) & 0xf;
|
|
87
|
-
if ((old = dict->trie[tr]))
|
|
88
|
-
goto replace_node;
|
|
89
|
-
|
|
90
|
-
/* no old, but we have a new node we need to initialize and add. */
|
|
91
|
-
*node = (fio_dict_s){.parent = dict, .trie_val = tr, .used = 1};
|
|
92
|
-
dict->trie[tr] = node;
|
|
93
|
-
return NULL;
|
|
94
|
-
|
|
95
|
-
replace_node:
|
|
96
|
-
/* We have an old node to be replaced with a new one. */
|
|
97
|
-
*node = *old;
|
|
98
|
-
node->used = 1;
|
|
99
|
-
dict->trie[tr] = node;
|
|
100
|
-
for (size_t i = 0; i < 16; i++) {
|
|
101
|
-
if (node->trie[i])
|
|
102
|
-
node->trie[i]->parent = node;
|
|
103
|
-
}
|
|
104
|
-
if (old->used)
|
|
105
|
-
return old;
|
|
106
|
-
return NULL;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Returns the old `fio_dict_s *` object associated with the key, if any.*/
|
|
110
|
-
fio_dict_s *fio_dict_remove(fio_dict_s *node) {
|
|
111
|
-
fio_dict_s *tmp;
|
|
112
|
-
fio_dict_s *dict = node->parent;
|
|
113
|
-
/* We need to remove the existing node and clear the branch if empty. */
|
|
114
|
-
if (fio_dict_isempty(node)) {
|
|
115
|
-
dict->trie[node->trie_val] = NULL;
|
|
116
|
-
while (fio_dict_isempty(dict)) {
|
|
117
|
-
if (dict->used || !dict->parent)
|
|
118
|
-
break;
|
|
119
|
-
tmp = dict;
|
|
120
|
-
dict = dict->parent;
|
|
121
|
-
dict->trie[tmp->trie_val] = NULL;
|
|
122
|
-
free(tmp);
|
|
123
|
-
}
|
|
124
|
-
if (node->used)
|
|
125
|
-
return node;
|
|
126
|
-
return NULL;
|
|
127
|
-
}
|
|
128
|
-
/* We need to place an alternative node. */
|
|
129
|
-
if (!node->used)
|
|
130
|
-
return NULL;
|
|
131
|
-
tmp = malloc(sizeof(fio_dict_s));
|
|
132
|
-
*tmp = *node;
|
|
133
|
-
tmp->used = 0;
|
|
134
|
-
for (size_t i = 0; i < 16; i++) {
|
|
135
|
-
if (tmp->trie[i])
|
|
136
|
-
tmp->trie[i]->parent = tmp;
|
|
137
|
-
}
|
|
138
|
-
return node;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** Returns a `fio_dict_s *` dictionary (or NULL) of all `prefix` children. */
|
|
142
|
-
fio_dict_s *fio_dict_step(fio_dict_s *dict, uint8_t prefix) {
|
|
143
|
-
return fio_dict_step_inline(dict, prefix);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Returns a `fio_dict_s *` dictionary (or NULL) of all `prefix` children. */
|
|
147
|
-
fio_dict_s *fio_dict_prefix(fio_dict_s *dict, void *prefix_, size_t len) {
|
|
148
|
-
return fio_dict_prefix_inline(dict, prefix_, len);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Creates a `fio_dict_s *` dictionary (if missing) for the `prefix`...
|
|
153
|
-
*
|
|
154
|
-
* After calling this function a node MUST be added to this dictionary, or
|
|
155
|
-
* memory leaks will occure.
|
|
156
|
-
*/
|
|
157
|
-
fio_dict_s *fio_dict_ensure_prefix(fio_dict_s *dict, void *prefix, size_t len) {
|
|
158
|
-
uint8_t *pos = prefix;
|
|
159
|
-
uint8_t tr;
|
|
160
|
-
|
|
161
|
-
while (dict && len) {
|
|
162
|
-
tr = *pos & 0xf;
|
|
163
|
-
if (!dict->trie[tr]) {
|
|
164
|
-
dict->trie[tr] = malloc(sizeof(fio_dict_s));
|
|
165
|
-
*dict->trie[tr] = (fio_dict_s){.trie_val = tr, .parent = dict};
|
|
166
|
-
}
|
|
167
|
-
dict = dict->trie[tr];
|
|
168
|
-
tr = (*pos >> 4) & 0xf;
|
|
169
|
-
if (!dict->trie[tr]) {
|
|
170
|
-
dict->trie[tr] = malloc(sizeof(fio_dict_s));
|
|
171
|
-
*dict->trie[tr] = (fio_dict_s){.trie_val = tr, .parent = dict};
|
|
172
|
-
}
|
|
173
|
-
dict = dict->trie[tr];
|
|
174
|
-
pos++;
|
|
175
|
-
len--;
|
|
176
|
-
}
|
|
177
|
-
return dict;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/** Traverses a dictionary, performing an action for each item. */
|
|
181
|
-
void fio_dict_each(fio_dict_s *dict,
|
|
182
|
-
void (*action)(fio_dict_s *node, void *arg), void *arg) {
|
|
183
|
-
if (!dict)
|
|
184
|
-
return;
|
|
185
|
-
fio_dict_s *child, *head = dict->parent, *to_call = NULL;
|
|
186
|
-
uint8_t tr;
|
|
187
|
-
tr = 0;
|
|
188
|
-
|
|
189
|
-
/* We use this to make sure that the function doesn't break if `to_call` is
|
|
190
|
-
* removed from the trie while we are iterating. */
|
|
191
|
-
#define test_callback() \
|
|
192
|
-
do { \
|
|
193
|
-
if (to_call) \
|
|
194
|
-
action(to_call, arg); \
|
|
195
|
-
to_call = dict; \
|
|
196
|
-
} while (0);
|
|
197
|
-
|
|
198
|
-
while (dict != head) {
|
|
199
|
-
top:
|
|
200
|
-
while (tr < 16) {
|
|
201
|
-
/* walk child */
|
|
202
|
-
if ((child = dict->trie[tr])) {
|
|
203
|
-
dict = child;
|
|
204
|
-
tr = 0;
|
|
205
|
-
goto top;
|
|
206
|
-
}
|
|
207
|
-
tr++;
|
|
208
|
-
}
|
|
209
|
-
if (dict->used)
|
|
210
|
-
test_callback();
|
|
211
|
-
tr = dict->trie_val + 1;
|
|
212
|
-
dict = dict->parent;
|
|
213
|
-
}
|
|
214
|
-
test_callback();
|
|
215
|
-
#undef test_callback
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
Traverses a dictionary, performing an action for each item.
|
|
221
|
-
|
|
222
|
-
based on the same matching behavior used by Redis... hopefully...
|
|
223
|
-
https://github.com/antirez/redis/blob/d680eb6dbdf2d2030cb96edfb089be1e2a775ac1/src/util.c#L47
|
|
224
|
-
*/
|
|
225
|
-
void fio_dict_each_match_glob(fio_dict_s *dict, void *pattern, size_t len,
|
|
226
|
-
void (*action)(fio_dict_s *node, void *arg),
|
|
227
|
-
void *arg) {
|
|
228
|
-
|
|
229
|
-
if (!dict || !pattern || !action)
|
|
230
|
-
return;
|
|
231
|
-
fio_dict_s *child, *head = dict->parent;
|
|
232
|
-
uint8_t *pos = pattern;
|
|
233
|
-
|
|
234
|
-
while (len && dict) {
|
|
235
|
-
|
|
236
|
-
if (*pos == '*') {
|
|
237
|
-
/* eat up all '*' and match whatever */
|
|
238
|
-
while (*pos == '*' && len) {
|
|
239
|
-
len--;
|
|
240
|
-
pos++;
|
|
241
|
-
}
|
|
242
|
-
if (!len) {
|
|
243
|
-
fio_dict_each(dict, action, arg);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
/* test each "tail"... (brrr). */
|
|
247
|
-
head = dict->parent;
|
|
248
|
-
uint8_t tr = 0;
|
|
249
|
-
while (dict != head) {
|
|
250
|
-
glob_top:
|
|
251
|
-
while (tr < 16) {
|
|
252
|
-
/* walk child */
|
|
253
|
-
if ((child = dict->trie[tr])) {
|
|
254
|
-
dict = child;
|
|
255
|
-
tr = 0;
|
|
256
|
-
goto glob_top;
|
|
257
|
-
}
|
|
258
|
-
tr++;
|
|
259
|
-
}
|
|
260
|
-
fio_dict_each_match_glob(dict, pos, len, action, arg);
|
|
261
|
-
tr = dict->trie_val + 1;
|
|
262
|
-
dict = dict->parent;
|
|
263
|
-
}
|
|
264
|
-
fio_dict_each_match_glob(dict, pos, len, action, arg);
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (*pos == '?') {
|
|
269
|
-
pos++;
|
|
270
|
-
len--;
|
|
271
|
-
for (size_t i = 0; i < 256; i++) {
|
|
272
|
-
if (dict->trie[i & 0xf])
|
|
273
|
-
fio_dict_each_match_glob(dict->trie[i & 0xf]->trie[(i >> 4) & 0xf],
|
|
274
|
-
pos, len, action, arg);
|
|
275
|
-
}
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (*pos == '[') {
|
|
280
|
-
int state = 0;
|
|
281
|
-
uint8_t map[256] = {0};
|
|
282
|
-
pos++;
|
|
283
|
-
len--;
|
|
284
|
-
if (*pos == '^') {
|
|
285
|
-
state = 1;
|
|
286
|
-
pos++;
|
|
287
|
-
len--;
|
|
288
|
-
}
|
|
289
|
-
if (!len)
|
|
290
|
-
return; /* pattern error */
|
|
291
|
-
while (*pos != ']' && len) {
|
|
292
|
-
if (*pos == '\\') {
|
|
293
|
-
pos++;
|
|
294
|
-
len--;
|
|
295
|
-
}
|
|
296
|
-
if (pos[1] == '-') {
|
|
297
|
-
if (len < 4) {
|
|
298
|
-
return; /* pattern error */
|
|
299
|
-
}
|
|
300
|
-
uint8_t end, start;
|
|
301
|
-
start = *pos;
|
|
302
|
-
pos += 2;
|
|
303
|
-
len -= 2;
|
|
304
|
-
if (*pos == '\\') {
|
|
305
|
-
pos++;
|
|
306
|
-
len--;
|
|
307
|
-
}
|
|
308
|
-
end = *pos;
|
|
309
|
-
if (start > end) {
|
|
310
|
-
uint8_t tmp;
|
|
311
|
-
tmp = start;
|
|
312
|
-
start = end;
|
|
313
|
-
end = tmp;
|
|
314
|
-
}
|
|
315
|
-
while (start < end)
|
|
316
|
-
map[start++] = 1;
|
|
317
|
-
map[end] = 1; /* prevent endless loop where `end == 255`*/
|
|
318
|
-
} else
|
|
319
|
-
map[*pos] = 1;
|
|
320
|
-
pos++;
|
|
321
|
-
len--;
|
|
322
|
-
}
|
|
323
|
-
if (!len) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
pos++;
|
|
327
|
-
len--;
|
|
328
|
-
for (size_t i = 0; i < 256; i++) {
|
|
329
|
-
/* code */
|
|
330
|
-
if (map[i] == state)
|
|
331
|
-
continue;
|
|
332
|
-
if (dict->trie[i & 0xf])
|
|
333
|
-
fio_dict_each_match_glob(dict->trie[i & 0xf]->trie[(i >> 4) & 0xf],
|
|
334
|
-
pos, len, action, arg);
|
|
335
|
-
}
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (*pos == '\\' && len > 1) {
|
|
340
|
-
pos++;
|
|
341
|
-
len--;
|
|
342
|
-
}
|
|
343
|
-
dict = fio_dict_step_inline(dict, *pos);
|
|
344
|
-
pos++;
|
|
345
|
-
len--;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (dict && dict->used)
|
|
349
|
-
action(dict, arg);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/** A binary glob matching helper. Returns 1 on match, otherwise returns 0. */
|
|
353
|
-
int fio_glob_match(uint8_t *data, size_t data_len, uint8_t *pattern,
|
|
354
|
-
size_t pat_len) {
|
|
355
|
-
/* adapted and rewritten, with thankfulness, from the code at:
|
|
356
|
-
* https://github.com/opnfv/kvmfornfv/blob/master/kernel/lib/glob.c
|
|
357
|
-
*
|
|
358
|
-
* Original version's copyright:
|
|
359
|
-
* Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
|
|
360
|
-
* Under the MIT license.
|
|
361
|
-
*/
|
|
362
|
-
|
|
363
|
-
/*
|
|
364
|
-
* Backtrack to previous * on mismatch and retry starting one
|
|
365
|
-
* character later in the string. Because * matches all characters
|
|
366
|
-
* (no exception for /), it can be easily proved that there's
|
|
367
|
-
* never a need to backtrack multiple levels.
|
|
368
|
-
*/
|
|
369
|
-
uint8_t *back_pat = NULL, *back_str = data;
|
|
370
|
-
size_t back_pat_len = 0, back_str_len = data_len;
|
|
371
|
-
|
|
372
|
-
/*
|
|
373
|
-
* Loop over each token (character or class) in pat, matching
|
|
374
|
-
* it against the remaining unmatched tail of str. Return false
|
|
375
|
-
* on mismatch, or true after matching the trailing nul bytes.
|
|
376
|
-
*/
|
|
377
|
-
while (data_len) {
|
|
378
|
-
uint8_t c = *data++;
|
|
379
|
-
uint8_t d = *pattern++;
|
|
380
|
-
data_len--;
|
|
381
|
-
pat_len--;
|
|
382
|
-
|
|
383
|
-
switch (d) {
|
|
384
|
-
case '?': /* Wildcard: anything goes */
|
|
385
|
-
break;
|
|
386
|
-
|
|
387
|
-
case '*': /* Any-length wildcard */
|
|
388
|
-
if (!pat_len) /* Optimize trailing * case */
|
|
389
|
-
return 1;
|
|
390
|
-
back_pat = pattern;
|
|
391
|
-
back_pat_len = pat_len;
|
|
392
|
-
back_str = --data; /* Allow zero-length match */
|
|
393
|
-
back_str_len = ++data_len;
|
|
394
|
-
break;
|
|
395
|
-
|
|
396
|
-
case '[': { /* Character class */
|
|
397
|
-
uint8_t match = 0, inverted = (*pattern == '^');
|
|
398
|
-
uint8_t *cls = pattern + inverted;
|
|
399
|
-
uint8_t a = *cls++;
|
|
400
|
-
|
|
401
|
-
/*
|
|
402
|
-
* Iterate over each span in the character class.
|
|
403
|
-
* A span is either a single character a, or a
|
|
404
|
-
* range a-b. The first span may begin with ']'.
|
|
405
|
-
*/
|
|
406
|
-
do {
|
|
407
|
-
uint8_t b = a;
|
|
408
|
-
|
|
409
|
-
if (cls[0] == '-' && cls[1] != ']') {
|
|
410
|
-
b = cls[1];
|
|
411
|
-
|
|
412
|
-
cls += 2;
|
|
413
|
-
if (a > b) {
|
|
414
|
-
uint8_t tmp = a;
|
|
415
|
-
a = b;
|
|
416
|
-
b = tmp;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
match |= (a <= c && c <= b);
|
|
420
|
-
} while ((a = *cls++) != ']');
|
|
421
|
-
|
|
422
|
-
if (match == inverted)
|
|
423
|
-
goto backtrack;
|
|
424
|
-
pat_len -= cls - pattern;
|
|
425
|
-
pattern = cls;
|
|
426
|
-
|
|
427
|
-
} break;
|
|
428
|
-
case '\\':
|
|
429
|
-
d = *pattern++;
|
|
430
|
-
pat_len--;
|
|
431
|
-
/*FALLTHROUGH*/
|
|
432
|
-
default: /* Literal character */
|
|
433
|
-
if (c == d)
|
|
434
|
-
break;
|
|
435
|
-
backtrack:
|
|
436
|
-
if (!back_pat)
|
|
437
|
-
return 0; /* No point continuing */
|
|
438
|
-
/* Try again from last *, one character later in str. */
|
|
439
|
-
pattern = back_pat;
|
|
440
|
-
data = ++back_str;
|
|
441
|
-
data_len = --back_str_len;
|
|
442
|
-
pat_len = back_pat_len;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return !data_len && !pat_len;
|
|
446
|
-
}
|