ruby-radix 0.0.2
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.
- data/.gemtest +0 -0
- data/History.txt +8 -0
- data/Manifest.txt +15 -0
- data/PostInstall.txt +3 -0
- data/README.rdoc +160 -0
- data/Rakefile +27 -0
- data/ext/extconf.rb +5 -0
- data/ext/radix.c +859 -0
- data/ext/radixlib.c +677 -0
- data/ext/radixlib.h +161 -0
- data/lib/ruby-radix.rb +6 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_helper.rb +3 -0
- data/test/test_ruby-radix.rb +127 -0
- metadata +129 -0
data/ext/radix.c
ADDED
@@ -0,0 +1,859 @@
|
|
1
|
+
/*
|
2
|
+
* Radix data-store for ruby
|
3
|
+
*
|
4
|
+
* Copyright (c) 2012, Internet Initiative Japan Inc.
|
5
|
+
* All rights reserved.
|
6
|
+
*
|
7
|
+
* Redistribution and use in source and binary forms, with or without
|
8
|
+
* modification, are permitted provided that the following conditions
|
9
|
+
* are met:
|
10
|
+
* 1. Redistributions of source code must retain the above copyright
|
11
|
+
* notice, this list of conditions and the following disclaimer.
|
12
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
13
|
+
* notice, this list of conditions and the following disclaimer in the
|
14
|
+
* documentation and/or other materials provided with the distribution.
|
15
|
+
*
|
16
|
+
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
17
|
+
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
18
|
+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19
|
+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
20
|
+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
21
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
22
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
23
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
24
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
25
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
*/
|
28
|
+
|
29
|
+
|
30
|
+
#include <arpa/inet.h>
|
31
|
+
#include "ruby.h"
|
32
|
+
#include "radixlib.h"
|
33
|
+
|
34
|
+
/*--------- Macros --------*/
|
35
|
+
#define GetRadix(obj, radixp) do {\
|
36
|
+
Data_Get_Struct(obj, struct radixdata, radixp); \
|
37
|
+
if (radixp == NULL) closed_radix(); \
|
38
|
+
if (radixp->rt[RT_IPV4] == NULL) closed_radix();\
|
39
|
+
if (radixp->rt[RT_IPV6] == NULL) closed_radix();\
|
40
|
+
} while (0)
|
41
|
+
|
42
|
+
#define RaiseModified(idx, idy) do {\
|
43
|
+
if (idx != idy) \
|
44
|
+
rb_raise(rb_eRuntimeError, \
|
45
|
+
"Radix tree modified during iteration"); \
|
46
|
+
} while (0)
|
47
|
+
|
48
|
+
#define RTNUM 2 /* IPv4 table + IPv6 table */
|
49
|
+
#define RT_IPV4 0
|
50
|
+
#define RT_IPV6 1
|
51
|
+
|
52
|
+
/*--------- Local Structures --------*/
|
53
|
+
struct radixdata {
|
54
|
+
radix_tree_t *rt[RTNUM]; /* Radix tree for IPv4/IPv6 */
|
55
|
+
unsigned int gen_id; /* Detect modification during iterations */
|
56
|
+
};
|
57
|
+
|
58
|
+
struct radixnode {
|
59
|
+
prefix_t prefix;
|
60
|
+
VALUE msg;
|
61
|
+
};
|
62
|
+
|
63
|
+
/*--------- Local Variables --------*/
|
64
|
+
static VALUE rb_cRadixNode;
|
65
|
+
|
66
|
+
|
67
|
+
/*--------- Prototypes --------*/
|
68
|
+
static VALUE rb_radix_initialize(int, VALUE *, VALUE);
|
69
|
+
static VALUE rb_radix_add(int, VALUE *, VALUE);
|
70
|
+
static VALUE rb_radix_search_best(int, VALUE *, VALUE);
|
71
|
+
static VALUE rb_radix_search_exact(int, VALUE *, VALUE);
|
72
|
+
static void closed_radix(void);
|
73
|
+
static prefix_t *args_to_prefix(char *, long);
|
74
|
+
static VALUE object_node_add(struct radixdata *, prefix_t *, VALUE, VALUE);
|
75
|
+
static void free_radixdata(struct radixdata *);
|
76
|
+
static VALUE rb_radix_aref(int, VALUE *, VALUE);
|
77
|
+
static VALUE rb_radix_keys(VALUE);
|
78
|
+
static VALUE rb_radix_values(VALUE);
|
79
|
+
static VALUE rb_radix_delete(int, VALUE *, VALUE);
|
80
|
+
static VALUE rb_radix_clear(VALUE);
|
81
|
+
static VALUE rb_radix_clear(VALUE);
|
82
|
+
static VALUE rb_radix_each_key(VALUE);
|
83
|
+
static VALUE rb_radix_each_value(VALUE);
|
84
|
+
static VALUE rb_radix_each_pair(VALUE);
|
85
|
+
static VALUE rb_radix_length(VALUE);
|
86
|
+
static VALUE rb_radix_to_hash(VALUE);
|
87
|
+
static void rn_free_func(radix_node_t *, void *);
|
88
|
+
static struct radixdata* newRadixData(void);
|
89
|
+
static void radix_mark(struct radixdata *);
|
90
|
+
static VALUE radix_s_alloc(VALUE);
|
91
|
+
static VALUE radixnode_s_alloc(VALUE);
|
92
|
+
static void rn_mark(struct radixnode *);
|
93
|
+
|
94
|
+
/*-------- class Radix --------*/
|
95
|
+
|
96
|
+
static int
|
97
|
+
init_radixdata(struct radixdata *radixp)
|
98
|
+
{
|
99
|
+
radix_tree_t *rt4, *rt6;
|
100
|
+
|
101
|
+
if ((rt4 = New_Radix()) == NULL)
|
102
|
+
return NULL;
|
103
|
+
if ((rt6 = New_Radix()) == NULL) {
|
104
|
+
xfree(rt4);
|
105
|
+
return NULL;
|
106
|
+
}
|
107
|
+
radixp->rt[RT_IPV4] = rt4;
|
108
|
+
radixp->rt[RT_IPV6] = rt6;
|
109
|
+
radixp->gen_id = 0;
|
110
|
+
|
111
|
+
return radixp;
|
112
|
+
}
|
113
|
+
|
114
|
+
static struct radixdata*
|
115
|
+
newRadixData(void)
|
116
|
+
{
|
117
|
+
struct radixdata *radixp;
|
118
|
+
|
119
|
+
radixp = ALLOC(struct radixdata);
|
120
|
+
init_radixdata(radixp);
|
121
|
+
|
122
|
+
return radixp;
|
123
|
+
}
|
124
|
+
|
125
|
+
static void
|
126
|
+
free_radixdata0(struct radixdata *radixp)
|
127
|
+
{
|
128
|
+
if (radixp == NULL)
|
129
|
+
return;
|
130
|
+
|
131
|
+
if (radixp->rt[RT_IPV4] != NULL)
|
132
|
+
Destroy_Radix(radixp->rt[RT_IPV4], rn_free_func, NULL);
|
133
|
+
|
134
|
+
if (radixp->rt[RT_IPV6] != NULL)
|
135
|
+
Destroy_Radix(radixp->rt[RT_IPV6], rn_free_func, NULL);
|
136
|
+
}
|
137
|
+
|
138
|
+
static void
|
139
|
+
free_radixdata(struct radixdata *radixp)
|
140
|
+
{
|
141
|
+
free_radixdata0(radixp);
|
142
|
+
xfree(radixp);
|
143
|
+
}
|
144
|
+
|
145
|
+
static prefix_t*
|
146
|
+
args_to_prefix(char *addr, long prefixlen)
|
147
|
+
{
|
148
|
+
prefix_t *prefix = NULL;
|
149
|
+
const char *errmsg;
|
150
|
+
|
151
|
+
if (addr == NULL)
|
152
|
+
rb_raise(rb_eRuntimeError, "No address specified");
|
153
|
+
|
154
|
+
if (addr != NULL) { /* Parse a string address */
|
155
|
+
if ((prefix = prefix_pton(addr, prefixlen, &errmsg)) == NULL)
|
156
|
+
rb_raise(rb_eRuntimeError, "Invalid address format");
|
157
|
+
}
|
158
|
+
if (prefix != NULL &&
|
159
|
+
prefix->family != AF_INET && prefix->family != AF_INET6) {
|
160
|
+
Deref_Prefix(prefix);
|
161
|
+
return NULL;
|
162
|
+
}
|
163
|
+
|
164
|
+
return prefix;
|
165
|
+
}
|
166
|
+
|
167
|
+
/*
|
168
|
+
* call-seq:
|
169
|
+
* Radix.new() => radix
|
170
|
+
*
|
171
|
+
* Open a radix database.
|
172
|
+
*/
|
173
|
+
static VALUE
|
174
|
+
rb_radix_initialize(int argc, VALUE *argv, VALUE self)
|
175
|
+
{
|
176
|
+
return self;
|
177
|
+
}
|
178
|
+
|
179
|
+
static void
|
180
|
+
radix_mark(struct radixdata *radixp)
|
181
|
+
{
|
182
|
+
radix_node_t *rn;
|
183
|
+
unsigned int gen_id_cur;
|
184
|
+
int i;
|
185
|
+
|
186
|
+
gen_id_cur = radixp->gen_id;
|
187
|
+
|
188
|
+
for (i = 0; i < RTNUM; i++) {
|
189
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
190
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
191
|
+
if (rn->data != NULL)
|
192
|
+
rb_gc_mark((VALUE)rn->data);
|
193
|
+
} RADIX_WALK_END;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
#define PICKRT(prefix, rno) (prefix->family == AF_INET6 ? rno->rt[RT_IPV6] : rno->rt[RT_IPV4])
|
198
|
+
|
199
|
+
static VALUE
|
200
|
+
object_node_add(struct radixdata *radp, prefix_t *prefix, VALUE self, VALUE msg)
|
201
|
+
{
|
202
|
+
radix_node_t *node;
|
203
|
+
struct radixnode *rn;
|
204
|
+
VALUE obj;
|
205
|
+
|
206
|
+
if ((node = radix_lookup(PICKRT(prefix, radp), prefix)) == NULL)
|
207
|
+
rb_raise(rb_eRuntimeError, "Cannot add prefix");
|
208
|
+
|
209
|
+
obj = rb_obj_alloc(rb_cRadixNode);
|
210
|
+
Data_Get_Struct(obj, struct radixnode, rn);
|
211
|
+
node->data = (void *)msg;
|
212
|
+
rn->msg = msg;
|
213
|
+
memcpy(&rn->prefix, node->prefix, sizeof(prefix_t));
|
214
|
+
radp->gen_id++;
|
215
|
+
|
216
|
+
return obj;
|
217
|
+
}
|
218
|
+
|
219
|
+
/*
|
220
|
+
* call-seq:
|
221
|
+
* radix.add(key[,prefixlen]) -> hash
|
222
|
+
*
|
223
|
+
* Stores the hash object in the database, indexed via the string key
|
224
|
+
* provided.
|
225
|
+
*/
|
226
|
+
static VALUE
|
227
|
+
rb_radix_add(int argc, VALUE *argv, VALUE self)
|
228
|
+
{
|
229
|
+
struct radixdata *radixp;
|
230
|
+
VALUE v_addr, v_plen;
|
231
|
+
prefix_t *prefix;
|
232
|
+
int plen;
|
233
|
+
VALUE obj;
|
234
|
+
|
235
|
+
GetRadix(self, radixp);
|
236
|
+
|
237
|
+
if (argc == 2) {
|
238
|
+
rb_scan_args(argc, argv, "2", &v_addr, &v_plen);
|
239
|
+
plen = FIX2INT(v_plen);
|
240
|
+
} else {
|
241
|
+
rb_scan_args(argc, argv, "1", &v_addr);
|
242
|
+
plen = -1;
|
243
|
+
}
|
244
|
+
|
245
|
+
prefix = args_to_prefix(RSTRING_PTR(v_addr), plen);
|
246
|
+
if (prefix == NULL)
|
247
|
+
return Qnil;
|
248
|
+
|
249
|
+
obj = object_node_add(radixp, prefix, self, Qtrue);
|
250
|
+
Deref_Prefix(prefix);
|
251
|
+
|
252
|
+
return obj;
|
253
|
+
}
|
254
|
+
|
255
|
+
static VALUE
|
256
|
+
rb_radix_add0(int argc, VALUE *argv, VALUE self)
|
257
|
+
{
|
258
|
+
struct radixdata *radixp;
|
259
|
+
VALUE v_addr, v_plen, v_msg;
|
260
|
+
prefix_t *prefix;
|
261
|
+
int plen;
|
262
|
+
VALUE obj;
|
263
|
+
|
264
|
+
GetRadix(self, radixp);
|
265
|
+
|
266
|
+
if (argc == 3) {
|
267
|
+
rb_scan_args(argc, argv, "3", &v_addr, &v_plen, &v_msg);
|
268
|
+
plen = FIX2INT(v_plen);
|
269
|
+
} else {
|
270
|
+
rb_scan_args(argc, argv, "2", &v_addr, &v_msg);
|
271
|
+
plen = -1;
|
272
|
+
}
|
273
|
+
|
274
|
+
prefix = args_to_prefix(RSTRING_PTR(v_addr), plen);
|
275
|
+
if (prefix == NULL)
|
276
|
+
return Qnil;
|
277
|
+
|
278
|
+
obj = object_node_add(radixp, prefix, self, v_msg);
|
279
|
+
Deref_Prefix(prefix);
|
280
|
+
|
281
|
+
return obj;
|
282
|
+
}
|
283
|
+
|
284
|
+
static VALUE rb_radix_delete(int argc, VALUE *argv, VALUE self)
|
285
|
+
{
|
286
|
+
struct radixdata *radixp;
|
287
|
+
VALUE v_addr, v_plen;
|
288
|
+
prefix_t *prefix;
|
289
|
+
radix_node_t *node;
|
290
|
+
int plen;
|
291
|
+
|
292
|
+
GetRadix(self, radixp);
|
293
|
+
|
294
|
+
if (argc == 2) {
|
295
|
+
rb_scan_args(argc, argv, "11", &v_addr, &v_plen);
|
296
|
+
plen = FIX2INT(v_plen);
|
297
|
+
} else {
|
298
|
+
rb_scan_args(argc, argv, "1", &v_addr);
|
299
|
+
plen = -1;
|
300
|
+
}
|
301
|
+
|
302
|
+
prefix = args_to_prefix(RSTRING_PTR(v_addr), plen);
|
303
|
+
if (prefix == NULL)
|
304
|
+
return Qnil;
|
305
|
+
|
306
|
+
if ((node = radix_search_exact(PICKRT(prefix, radixp), prefix)) == NULL) {
|
307
|
+
Deref_Prefix(prefix);
|
308
|
+
return Qnil;
|
309
|
+
}
|
310
|
+
if (node->data != NULL) {
|
311
|
+
node->data = NULL;
|
312
|
+
}
|
313
|
+
|
314
|
+
radix_remove(PICKRT(prefix, radixp), node);
|
315
|
+
Deref_Prefix(prefix);
|
316
|
+
|
317
|
+
radixp->gen_id++;
|
318
|
+
|
319
|
+
return Qnil;
|
320
|
+
}
|
321
|
+
|
322
|
+
/*
|
323
|
+
* call-seq:
|
324
|
+
* radix.search_best(key[, prefixlen]) -> hash
|
325
|
+
*
|
326
|
+
* Return a value from the database by locating the key string
|
327
|
+
* provided.
|
328
|
+
* Search strategy is to match best suited for the key.
|
329
|
+
* If the key is not found, returns nil.
|
330
|
+
*/
|
331
|
+
static VALUE
|
332
|
+
rb_radix_search_best(int argc, VALUE *argv, VALUE self)
|
333
|
+
{
|
334
|
+
struct radixdata *radixp;
|
335
|
+
radix_node_t *node;
|
336
|
+
struct radixnode *rn;
|
337
|
+
VALUE obj;
|
338
|
+
VALUE v_addr, v_plen;
|
339
|
+
prefix_t *prefix;
|
340
|
+
int plen;
|
341
|
+
|
342
|
+
GetRadix(self, radixp);
|
343
|
+
|
344
|
+
if (argc == 2) {
|
345
|
+
rb_scan_args(argc, argv, "11", &v_addr, &v_plen);
|
346
|
+
plen = FIX2INT(v_plen);
|
347
|
+
} else {
|
348
|
+
rb_scan_args(argc, argv, "1", &v_addr);
|
349
|
+
plen = -1;
|
350
|
+
}
|
351
|
+
|
352
|
+
prefix = args_to_prefix(RSTRING_PTR(v_addr), plen);
|
353
|
+
if (prefix == NULL)
|
354
|
+
return Qnil;
|
355
|
+
|
356
|
+
if ((node = radix_search_best(PICKRT(prefix, radixp), prefix)) == NULL
|
357
|
+
|| node->data == NULL) {
|
358
|
+
Deref_Prefix(prefix);
|
359
|
+
return Qnil;
|
360
|
+
}
|
361
|
+
Deref_Prefix(prefix);
|
362
|
+
|
363
|
+
obj = rb_obj_alloc(rb_cRadixNode);
|
364
|
+
Data_Get_Struct(obj, struct radixnode, rn);
|
365
|
+
rn->msg = (VALUE)node->data;
|
366
|
+
memcpy(&rn->prefix, node->prefix, sizeof(prefix_t));
|
367
|
+
|
368
|
+
return obj;
|
369
|
+
}
|
370
|
+
|
371
|
+
/*
|
372
|
+
* call-seq:
|
373
|
+
* radix.search_best(key[, prefixlen]) -> hash
|
374
|
+
*
|
375
|
+
* Return a value from the database by locating the key string
|
376
|
+
* provided.
|
377
|
+
* Search strategy is to match exactly. If the key is not found,
|
378
|
+
* returns nil.
|
379
|
+
*/
|
380
|
+
static VALUE
|
381
|
+
rb_radix_search_exact(int argc, VALUE *argv, VALUE self)
|
382
|
+
{
|
383
|
+
struct radixdata *radixp;
|
384
|
+
radix_node_t *node;
|
385
|
+
struct radixnode *rn;
|
386
|
+
VALUE v_addr, v_plen;
|
387
|
+
VALUE obj;
|
388
|
+
prefix_t *prefix;
|
389
|
+
int plen;
|
390
|
+
|
391
|
+
GetRadix(self, radixp);
|
392
|
+
|
393
|
+
if (argc == 2) {
|
394
|
+
rb_scan_args(argc, argv, "11", &v_addr, &v_plen);
|
395
|
+
plen = FIX2INT(v_plen);
|
396
|
+
} else {
|
397
|
+
rb_scan_args(argc, argv, "1", &v_addr);
|
398
|
+
plen = -1;
|
399
|
+
}
|
400
|
+
|
401
|
+
prefix = args_to_prefix(RSTRING_PTR(v_addr), plen);
|
402
|
+
if (prefix == NULL)
|
403
|
+
return Qnil;
|
404
|
+
|
405
|
+
if ((node = radix_search_exact(PICKRT(prefix, radixp), prefix)) == NULL
|
406
|
+
|| node->data == NULL) {
|
407
|
+
Deref_Prefix(prefix);
|
408
|
+
return Qnil;
|
409
|
+
}
|
410
|
+
Deref_Prefix(prefix);
|
411
|
+
|
412
|
+
obj = rb_obj_alloc(rb_cRadixNode);
|
413
|
+
Data_Get_Struct(obj, struct radixnode, rn);
|
414
|
+
rn->msg = (VALUE)node->data;
|
415
|
+
memcpy(&rn->prefix, node->prefix, sizeof(prefix_t));
|
416
|
+
|
417
|
+
return obj;
|
418
|
+
}
|
419
|
+
|
420
|
+
/*
|
421
|
+
* call-seq:
|
422
|
+
* radix[key] -> hash value or nil
|
423
|
+
*
|
424
|
+
* Return a value from the database by locating the key string
|
425
|
+
* provided. If the key is not found, returns nil.
|
426
|
+
*/
|
427
|
+
static VALUE
|
428
|
+
rb_radix_aref(int argc, VALUE *argv, VALUE self)
|
429
|
+
{
|
430
|
+
return rb_radix_search_best(argc, argv, self);
|
431
|
+
}
|
432
|
+
|
433
|
+
|
434
|
+
/*
|
435
|
+
* call-seq:
|
436
|
+
* radix.length -> integer
|
437
|
+
*
|
438
|
+
* Returns the number of entries in the database.
|
439
|
+
*/
|
440
|
+
static VALUE
|
441
|
+
rb_radix_length(VALUE self)
|
442
|
+
{
|
443
|
+
struct radixdata *radixp;
|
444
|
+
radix_node_t *rn;
|
445
|
+
unsigned int rn_count = 0;
|
446
|
+
unsigned int gen_id_cur;
|
447
|
+
int i;
|
448
|
+
|
449
|
+
GetRadix(self, radixp);
|
450
|
+
|
451
|
+
gen_id_cur = radixp->gen_id;
|
452
|
+
|
453
|
+
for (i = 0; i < RTNUM; i++) {
|
454
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
455
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
456
|
+
if (rn->data != NULL)
|
457
|
+
rn_count++;
|
458
|
+
} RADIX_WALK_END;
|
459
|
+
}
|
460
|
+
|
461
|
+
return INT2FIX(rn_count);
|
462
|
+
}
|
463
|
+
|
464
|
+
/*
|
465
|
+
* call-seq:
|
466
|
+
* radix.keys -> array
|
467
|
+
*
|
468
|
+
* Returns an array of all the string keys in the database.
|
469
|
+
*/
|
470
|
+
static VALUE
|
471
|
+
rb_radix_keys(VALUE self)
|
472
|
+
{
|
473
|
+
struct radixdata *radixp;
|
474
|
+
radix_node_t *rn;
|
475
|
+
VALUE ary;
|
476
|
+
char prefix[256];
|
477
|
+
unsigned int gen_id_cur;
|
478
|
+
int i;
|
479
|
+
|
480
|
+
GetRadix(self, radixp);
|
481
|
+
|
482
|
+
ary = rb_ary_new();
|
483
|
+
gen_id_cur = radixp->gen_id;
|
484
|
+
|
485
|
+
for (i = 0; i < RTNUM; i++) {
|
486
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
487
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
488
|
+
if (rn->data != NULL) {
|
489
|
+
prefix_ntop(rn->prefix, prefix, sizeof(prefix));
|
490
|
+
rb_ary_push(ary, rb_tainted_str_new(
|
491
|
+
prefix, strlen(prefix)));
|
492
|
+
}
|
493
|
+
} RADIX_WALK_END;
|
494
|
+
}
|
495
|
+
|
496
|
+
return ary;
|
497
|
+
}
|
498
|
+
|
499
|
+
/*
|
500
|
+
* call-seq:
|
501
|
+
* radix.values -> array
|
502
|
+
*
|
503
|
+
* Returns an array of all the string values in the database.
|
504
|
+
*/
|
505
|
+
static VALUE
|
506
|
+
rb_radix_values(VALUE self)
|
507
|
+
{
|
508
|
+
struct radixdata *radixp;
|
509
|
+
radix_node_t *rn;
|
510
|
+
VALUE ary;
|
511
|
+
unsigned int gen_id_cur;
|
512
|
+
int i;
|
513
|
+
|
514
|
+
GetRadix(self, radixp);
|
515
|
+
|
516
|
+
ary = rb_ary_new();
|
517
|
+
gen_id_cur = radixp->gen_id;
|
518
|
+
|
519
|
+
for (i = 0; i < RTNUM; i++) {
|
520
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
521
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
522
|
+
if (rn->data != NULL) {
|
523
|
+
rb_ary_push(ary, (VALUE)rn->data);
|
524
|
+
}
|
525
|
+
} RADIX_WALK_END;
|
526
|
+
}
|
527
|
+
|
528
|
+
return ary;
|
529
|
+
}
|
530
|
+
|
531
|
+
static void
|
532
|
+
rn_free_func(radix_node_t *rn, void *cbctx)
|
533
|
+
{
|
534
|
+
rn->data = NULL;
|
535
|
+
}
|
536
|
+
|
537
|
+
/*
|
538
|
+
* call-seq:
|
539
|
+
* radix.clear
|
540
|
+
*
|
541
|
+
* Deletes all data from the database.
|
542
|
+
*/
|
543
|
+
static VALUE
|
544
|
+
rb_radix_clear(VALUE self)
|
545
|
+
{
|
546
|
+
struct radixdata *radixp;
|
547
|
+
|
548
|
+
GetRadix(self, radixp);
|
549
|
+
free_radixdata0(radixp);
|
550
|
+
init_radixdata(radixp);
|
551
|
+
|
552
|
+
return self;
|
553
|
+
}
|
554
|
+
|
555
|
+
/*
|
556
|
+
* call-seq:
|
557
|
+
* radix.each_key {|key| block} -> self
|
558
|
+
*
|
559
|
+
* Calls the block once for each key string in the database. Returns self.
|
560
|
+
*/
|
561
|
+
static VALUE
|
562
|
+
rb_radix_each_key(VALUE self)
|
563
|
+
{
|
564
|
+
struct radixdata *radixp;
|
565
|
+
radix_node_t *rn;
|
566
|
+
char prefix[256];
|
567
|
+
unsigned int gen_id_cur;
|
568
|
+
int i;
|
569
|
+
|
570
|
+
GetRadix(self, radixp);
|
571
|
+
|
572
|
+
gen_id_cur = radixp->gen_id;
|
573
|
+
|
574
|
+
for (i = 0; i < RTNUM; i++) {
|
575
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
576
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
577
|
+
if (rn->data != NULL) {
|
578
|
+
prefix_ntop(rn->prefix, prefix, sizeof(prefix));
|
579
|
+
rb_yield(rb_tainted_str_new(prefix,
|
580
|
+
strlen(prefix)));
|
581
|
+
}
|
582
|
+
} RADIX_WALK_END;
|
583
|
+
}
|
584
|
+
|
585
|
+
return self;
|
586
|
+
}
|
587
|
+
|
588
|
+
/*
|
589
|
+
* call-seq:
|
590
|
+
* radix.each_value {|val| block} -> self
|
591
|
+
*
|
592
|
+
* Calls the block once for each value string in the database. Returns self.
|
593
|
+
*/
|
594
|
+
static VALUE
|
595
|
+
rb_radix_each_value(VALUE self)
|
596
|
+
{
|
597
|
+
struct radixdata *radixp;
|
598
|
+
radix_node_t *rn;
|
599
|
+
unsigned int gen_id_cur;
|
600
|
+
int i;
|
601
|
+
|
602
|
+
GetRadix(self, radixp);
|
603
|
+
|
604
|
+
gen_id_cur = radixp->gen_id;
|
605
|
+
|
606
|
+
for (i = 0; i < RTNUM; i++) {
|
607
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
608
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
609
|
+
if (rn->data != NULL) {
|
610
|
+
rb_yield((VALUE)rn->data);
|
611
|
+
}
|
612
|
+
} RADIX_WALK_END;
|
613
|
+
}
|
614
|
+
|
615
|
+
return self;
|
616
|
+
}
|
617
|
+
|
618
|
+
/*
|
619
|
+
* call-seq:
|
620
|
+
* radix.each {|key, value| block} -> self
|
621
|
+
*
|
622
|
+
* Calls the block once for each [key, value] pair int the database.
|
623
|
+
* Returns self.
|
624
|
+
*/
|
625
|
+
static VALUE
|
626
|
+
rb_radix_each_pair(VALUE self)
|
627
|
+
{
|
628
|
+
struct radixdata *radixp;
|
629
|
+
radix_node_t *rn;
|
630
|
+
char prefix[256];
|
631
|
+
unsigned int gen_id_cur;
|
632
|
+
VALUE keystr;
|
633
|
+
int i;
|
634
|
+
|
635
|
+
GetRadix(self, radixp);
|
636
|
+
|
637
|
+
gen_id_cur = radixp->gen_id;
|
638
|
+
|
639
|
+
for (i = 0; i < RTNUM; i++) {
|
640
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
641
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
642
|
+
if (rn->data != NULL) {
|
643
|
+
prefix_ntop(rn->prefix, prefix, sizeof(prefix));
|
644
|
+
keystr = rb_tainted_str_new(prefix,
|
645
|
+
strlen(prefix));
|
646
|
+
rb_yield(rb_assoc_new(keystr, (VALUE)rn->data));
|
647
|
+
}
|
648
|
+
} RADIX_WALK_END;
|
649
|
+
}
|
650
|
+
|
651
|
+
return self;
|
652
|
+
}
|
653
|
+
|
654
|
+
/*
|
655
|
+
* call-seq:
|
656
|
+
* radix.to_hash -> hash
|
657
|
+
*
|
658
|
+
* Converts the contents of the database to an in-memory Hash object, and
|
659
|
+
* returns it.
|
660
|
+
*/
|
661
|
+
static VALUE
|
662
|
+
rb_radix_to_hash(VALUE self)
|
663
|
+
{
|
664
|
+
struct radixdata *radixp;
|
665
|
+
radix_node_t *rn;
|
666
|
+
char prefix[256];
|
667
|
+
unsigned int gen_id_cur;
|
668
|
+
VALUE keystr;
|
669
|
+
VALUE hash;
|
670
|
+
int i;
|
671
|
+
|
672
|
+
GetRadix(self, radixp);
|
673
|
+
|
674
|
+
gen_id_cur = radixp->gen_id;
|
675
|
+
|
676
|
+
hash = rb_hash_new();
|
677
|
+
for (i = 0; i < RTNUM; i++) {
|
678
|
+
RADIX_WALK(radixp->rt[i]->head, rn) {
|
679
|
+
RaiseModified(gen_id_cur, radixp->gen_id);
|
680
|
+
if (rn->data != NULL) {
|
681
|
+
prefix_ntop(rn->prefix, prefix, sizeof(prefix));
|
682
|
+
keystr = rb_tainted_str_new(prefix,
|
683
|
+
strlen(prefix));
|
684
|
+
rb_hash_aset(hash, keystr, (VALUE)rn->data);
|
685
|
+
}
|
686
|
+
} RADIX_WALK_END;
|
687
|
+
}
|
688
|
+
|
689
|
+
return hash;
|
690
|
+
}
|
691
|
+
|
692
|
+
static void
|
693
|
+
closed_radix(void)
|
694
|
+
{
|
695
|
+
rb_raise(rb_eRuntimeError, "closed Radix tree");
|
696
|
+
}
|
697
|
+
|
698
|
+
static VALUE
|
699
|
+
radix_s_alloc(VALUE klass)
|
700
|
+
{
|
701
|
+
struct radixdata *radixp;
|
702
|
+
|
703
|
+
radixp = newRadixData();
|
704
|
+
if (radixp == NULL)
|
705
|
+
rb_raise(rb_eRuntimeError, "Initialize error");
|
706
|
+
|
707
|
+
Data_Wrap_Struct(klass, radix_mark, free_radixdata, radixp);
|
708
|
+
}
|
709
|
+
|
710
|
+
static void
|
711
|
+
rn_mark(struct radixnode *rn)
|
712
|
+
{
|
713
|
+
rb_gc_mark(rn->msg);
|
714
|
+
}
|
715
|
+
|
716
|
+
static void
|
717
|
+
free_rn(struct radixnode *rn)
|
718
|
+
{
|
719
|
+
xfree(rn);
|
720
|
+
}
|
721
|
+
|
722
|
+
static VALUE
|
723
|
+
radixnode_s_alloc(VALUE klass)
|
724
|
+
{
|
725
|
+
struct radixnode *rn;
|
726
|
+
VALUE obj;
|
727
|
+
|
728
|
+
obj = Data_Make_Struct(klass, struct radixnode, rn_mark, free_rn, rn);
|
729
|
+
rn->msg = Qnil;
|
730
|
+
|
731
|
+
return obj;
|
732
|
+
}
|
733
|
+
|
734
|
+
static VALUE
|
735
|
+
rb_rn_msg_get(VALUE self)
|
736
|
+
{
|
737
|
+
struct radixnode *rn;
|
738
|
+
|
739
|
+
Data_Get_Struct(self, struct radixnode, rn);
|
740
|
+
|
741
|
+
if (rn == NULL)
|
742
|
+
return Qnil;
|
743
|
+
|
744
|
+
return rn->msg;
|
745
|
+
}
|
746
|
+
|
747
|
+
static VALUE
|
748
|
+
rb_rn_prefix_get(VALUE self)
|
749
|
+
{
|
750
|
+
struct radixnode *rn;
|
751
|
+
char prefix[256];
|
752
|
+
|
753
|
+
Data_Get_Struct(self, struct radixnode, rn);
|
754
|
+
|
755
|
+
prefix_ntop(&rn->prefix, prefix, sizeof(prefix));
|
756
|
+
|
757
|
+
return rb_tainted_str_new(prefix, strlen(prefix));
|
758
|
+
}
|
759
|
+
|
760
|
+
static VALUE
|
761
|
+
rb_rn_network_get(VALUE self)
|
762
|
+
{
|
763
|
+
struct radixnode *rn;
|
764
|
+
char prefix[256];
|
765
|
+
|
766
|
+
Data_Get_Struct(self, struct radixnode, rn);
|
767
|
+
|
768
|
+
prefix_addr_ntop(&rn->prefix, prefix, sizeof(prefix));
|
769
|
+
|
770
|
+
return rb_tainted_str_new(prefix, strlen(prefix));
|
771
|
+
}
|
772
|
+
|
773
|
+
static VALUE
|
774
|
+
rb_rn_prefixlen_get(VALUE self)
|
775
|
+
{
|
776
|
+
struct radixnode *rn;
|
777
|
+
|
778
|
+
Data_Get_Struct(self, struct radixnode, rn);
|
779
|
+
|
780
|
+
return INT2FIX(rn->prefix.bitlen);
|
781
|
+
}
|
782
|
+
|
783
|
+
static VALUE
|
784
|
+
rb_rn_af_get(VALUE self)
|
785
|
+
{
|
786
|
+
struct radixnode *rn;
|
787
|
+
int family;
|
788
|
+
|
789
|
+
Data_Get_Struct(self, struct radixnode, rn);
|
790
|
+
|
791
|
+
if (rn->prefix.family == AF_INET)
|
792
|
+
family = 4;
|
793
|
+
else
|
794
|
+
family = 6;
|
795
|
+
return INT2FIX(family);
|
796
|
+
}
|
797
|
+
|
798
|
+
|
799
|
+
/*
|
800
|
+
* Documented by sogabe sogabe@iij.ad.jp
|
801
|
+
* = Introduction
|
802
|
+
*
|
803
|
+
* The Radix class provides a wrapper to a Radix-style Database
|
804
|
+
* Manager library.
|
805
|
+
*
|
806
|
+
* = Example
|
807
|
+
*
|
808
|
+
* require 'radix'
|
809
|
+
* r = Radix.new
|
810
|
+
* node = r.add("192.168.0.0", 24)
|
811
|
+
* node = r.add("172.31.0.0/16")
|
812
|
+
* r["172.16.0.0/16"] = "Hello Radix!"
|
813
|
+
* node = r["172.16.0.1"]
|
814
|
+
* node.msg
|
815
|
+
* node.prefix
|
816
|
+
* node.prefixlen
|
817
|
+
* node.af
|
818
|
+
* node.network
|
819
|
+
* r.search_best("192.168.0.1", 32)
|
820
|
+
* r.search_exact("192.168.0.0/24")
|
821
|
+
* r.delete("192.168.0.0/24")
|
822
|
+
* r.each_pair do |k, v|
|
823
|
+
* print k, " ", v.msg, "\n"
|
824
|
+
* end
|
825
|
+
*/
|
826
|
+
void Init_radix()
|
827
|
+
{
|
828
|
+
VALUE rb_cRadix;
|
829
|
+
|
830
|
+
rb_cRadix = rb_define_class("Radix", rb_cObject);
|
831
|
+
|
832
|
+
rb_cRadixNode = rb_define_class("RadixNode", rb_cObject);
|
833
|
+
|
834
|
+
rb_define_alloc_func(rb_cRadix, radix_s_alloc);
|
835
|
+
rb_define_alloc_func(rb_cRadixNode, radixnode_s_alloc);
|
836
|
+
|
837
|
+
rb_define_method(rb_cRadix, "initialize", rb_radix_initialize, -1);
|
838
|
+
rb_define_method(rb_cRadix, "add", rb_radix_add, -1);
|
839
|
+
rb_define_method(rb_cRadix, "search_best", rb_radix_search_best, -1);
|
840
|
+
rb_define_method(rb_cRadix, "search_exact", rb_radix_search_exact, -1);
|
841
|
+
rb_define_method(rb_cRadix, "[]", rb_radix_aref, -1);
|
842
|
+
rb_define_method(rb_cRadix, "[]=", rb_radix_add0, -1);
|
843
|
+
rb_define_method(rb_cRadix, "store", rb_radix_add, -1);
|
844
|
+
rb_define_method(rb_cRadix, "keys", rb_radix_keys, 0);
|
845
|
+
rb_define_method(rb_cRadix, "values", rb_radix_values, 0);
|
846
|
+
rb_define_method(rb_cRadix, "delete", rb_radix_delete, -1);
|
847
|
+
rb_define_method(rb_cRadix, "clear", rb_radix_clear, 0);
|
848
|
+
rb_define_method(rb_cRadix, "each_key", rb_radix_each_key, 0);
|
849
|
+
rb_define_method(rb_cRadix, "each_value", rb_radix_each_value, 0);
|
850
|
+
rb_define_method(rb_cRadix, "each_pair", rb_radix_each_pair, 0);
|
851
|
+
rb_define_method(rb_cRadix, "length", rb_radix_length, 0);
|
852
|
+
rb_define_method(rb_cRadix, "to_hash", rb_radix_to_hash, 0);
|
853
|
+
|
854
|
+
rb_define_method(rb_cRadixNode, "msg", rb_rn_msg_get, 0);
|
855
|
+
rb_define_method(rb_cRadixNode, "prefix", rb_rn_prefix_get, 0);
|
856
|
+
rb_define_method(rb_cRadixNode, "network", rb_rn_network_get, 0);
|
857
|
+
rb_define_method(rb_cRadixNode, "family", rb_rn_af_get, 0);
|
858
|
+
rb_define_method(rb_cRadixNode, "prefixlen", rb_rn_prefixlen_get, 0);
|
859
|
+
}
|