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/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
+ }