ruby-radix 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+ }