rpatricia 0.07 → 0.08

Sign up to get free protection for your applications and to get access to all the features.
data/Changes CHANGED
@@ -1,3 +1,7 @@
1
+ 0.08 2011/0812
2
+ - IPv6 support: Patricia.new(:AF_INET6)
3
+ - minor internal cleanups and speedups
4
+
1
5
  0.07 2010/09/23
2
6
  - fix segfault from unpredictable GC ordering
3
7
  when node objects outlive the trees they come from
data/README CHANGED
@@ -60,9 +60,11 @@ new:
60
60
 
61
61
  pt = Patricia.new
62
62
 
63
- This is the class' constructor - it returns a Patricia object. For
64
- now, the constructor takes no arguments, and defaults to creating a
65
- tree which uses AF_INET IPv4 address and mask values as keys.
63
+ This is the class' constructor - it returns a Patricia object for
64
+ handling IPv4 addresses. To handle IPv6 addresses (only),
65
+ Patricia.new may be called with an additional argument:
66
+
67
+ pt = Patricia.new(:AF_INET6)
66
68
 
67
69
  The Patricia object will be destroyed automatically when there are
68
70
  no longer any references to it.
@@ -74,7 +76,8 @@ add:
74
76
  specification in canonical form, e.g. ``10.0.0.0/8'', where the
75
77
  number after the slash represents the number of bits in the
76
78
  netmask. If no mask width is specified, the longest possible mask
77
- is assumed, i.e. 32 bits for AF_INET addresses.
79
+ is assumed, i.e. 32 bits for AF_INET addresses and 128 bits for
80
+ AF_INET6 addresses.
78
81
 
79
82
  The second argument, user_data, is optional. If supplied, it
80
83
  should be a STRING object specifying the user data that will be
@@ -89,6 +92,12 @@ add:
89
92
  On success, this method returns the object of the Patricia Trie
90
93
  node.
91
94
 
95
+ family:
96
+
97
+ Returns either :AF_INET or :AF_INET6 symbol depending on how the
98
+ object was initialized. A Patricia object may only handle IPv4 or
99
+ IPv6 addresses.
100
+
92
101
  add_node: An alias of add.
93
102
 
94
103
  search_best:
@@ -103,7 +112,7 @@ search_best:
103
112
  canonical form, e.g. ``10.0.0.0/8'', where the number after the
104
113
  slash represents the number of bits in the netmask. If no mask
105
114
  width value is specified, the longest mask is assumed, i.e. 32
106
- bits for AF_INET addresses.
115
+ bits for AF_INET addresses and 128 bits for AF_INET6 addresses.
107
116
 
108
117
  If a matching node is found in the Patricia Trie, this method
109
118
  returns the object of the node. This method returns nil on
@@ -181,6 +190,7 @@ prefixlen:
181
190
  This method returns the prefix length of the Patricia Trie
182
191
  node.
183
192
 
184
- AUTHOR
185
- ------
193
+ AUTHORS
194
+ -------
186
195
  Tatsuya Mori <mori.tatsuya@gmail.com>
196
+ Eric Wong <normalperson@yhbt.net>
@@ -67,142 +67,37 @@ comp_with_mask (void *addr, void *dest, u_int mask)
67
67
  return (0);
68
68
  }
69
69
 
70
- /* inet_pton substitute implementation
71
- * Uses inet_addr to convert an IP address in dotted decimal notation into
72
- * unsigned long and copies the result to dst.
73
- * Only supports AF_INET. Follows standard error return conventions of
74
- * inet_pton.
75
- */
76
- int
77
- inet_pton (int af, const char *src, void *dst)
78
- {
79
- u_long result;
80
-
81
- if (af == AF_INET) {
82
- result = inet_addr(src);
83
- if (result == -1)
84
- return 0;
85
- else {
86
- memcpy (dst, &result, 4);
87
- return 1;
88
- }
89
- }
90
- #ifdef NT
91
- #ifdef HAVE_IPV6
92
- else if (af == AF_INET6) {
93
- struct in6_addr Address;
94
- return (inet6_addr(src, &Address));
95
- }
96
- #endif /* HAVE_IPV6 */
97
- #endif /* NT */
98
- #ifndef NT
99
- else {
100
-
101
- errno = EAFNOSUPPORT;
102
- return -1;
103
- }
104
- #endif /* NT */
105
- }
106
-
107
- /* this allows imcomplete prefix */
108
- int
109
- my_inet_pton (int af, const char *src, void *dst)
110
- {
111
- if (af == AF_INET) {
112
- int i, c, val;
113
- u_char xp[4] = {0, 0, 0, 0};
114
-
115
- for (i = 0; ; i++) {
116
- c = *src++;
117
- if (!isdigit (c))
118
- return (-1);
119
- val = 0;
120
- do {
121
- val = val * 10 + c - '0';
122
- if (val > 255)
123
- return (0);
124
- c = *src++;
125
- } while (c && isdigit (c));
126
- xp[i] = val;
127
- if (c == '\0')
128
- break;
129
- if (c != '.')
130
- return (0);
131
- if (i >= 3)
132
- return (0);
133
- }
134
- memcpy (dst, xp, 4);
135
- return (1);
136
- #ifdef HAVE_IPV6
137
- } else if (af == AF_INET6) {
138
- return (inet_pton (af, src, dst));
139
- #endif /* HAVE_IPV6 */
140
- } else {
141
- #ifndef NT
142
- errno = EAFNOSUPPORT;
143
- #endif /* NT */
144
- return -1;
145
- }
146
- }
147
-
148
70
  /*
149
71
  * convert prefix information to ascii string with length
150
- * thread safe and (almost) re-entrant implementation
72
+ * thread safe and re-entrant implementation
73
+ *
74
+ * buff must be at least PATRICIA_MAXSTRLEN bytes large if with_len is true
75
+ * buff must be at least INET6_ADDRSTRLEN bytes large if with_len is false
151
76
  */
152
77
  char *
153
78
  prefix_toa2x (prefix_t *prefix, char *buff, int with_len)
154
79
  {
155
- if (prefix == NULL)
156
- return ("(Null)");
157
- assert (prefix->ref_count >= 0);
158
- if (buff == NULL) {
159
-
160
- struct buffer {
161
- char buffs[16][48+5];
162
- u_int i;
163
- } *buffp;
164
-
165
- # if 0
166
- THREAD_SPECIFIC_DATA (struct buffer, buffp, 1);
167
- # else
168
- { /* for scope only */
169
- static struct buffer local_buff;
170
- buffp = &local_buff;
171
- }
172
- # endif
173
- if (buffp == NULL) {
174
- /* XXX should we report an error? */
175
- return (NULL);
176
- }
80
+ const char *dst;
177
81
 
178
- buff = buffp->buffs[buffp->i++%16];
179
- }
180
- if (prefix->family == AF_INET) {
181
- u_char *a;
182
- assert (prefix->bitlen <= 32);
183
- a = prefix_touchar (prefix);
184
- if (with_len) {
185
- sprintf (buff, "%d.%d.%d.%d/%d", a[0], a[1], a[2], a[3],
186
- prefix->bitlen);
187
- }
188
- else {
189
- sprintf (buff, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
190
- }
191
- return (buff);
192
- }
193
- #ifdef HAVE_IPV6
194
- else if (prefix->family == AF_INET6) {
195
- char *r;
196
- r = (char *) inet_ntop (AF_INET6, &prefix->add.sin6, buff, 48 /* a guess value */ );
197
- if (r && with_len) {
198
- assert (prefix->bitlen <= 128);
199
- sprintf (buff + strlen (buff), "/%d", prefix->bitlen);
200
- }
201
- return (buff);
202
- }
203
- #endif /* HAVE_IPV6 */
204
- else
205
- return (NULL);
82
+ assert(prefix && "NULL prefix not allowed");
83
+ assert(prefix->ref_count >= 0);
84
+ assert(buff != NULL && "buffer must be specified");
85
+
86
+ switch (prefix->family) {
87
+ case AF_INET:
88
+ assert(prefix->bitlen <= 32 && "bitlen > 32 for AF_INET");
89
+ break;
90
+ case AF_INET6:
91
+ assert(prefix->bitlen <= 128 && "bitlen > 128 for AF_INET6");
92
+ break;
93
+ default:
94
+ assert(0 && "unknown address family (memory corruption?)");
95
+ }
96
+ dst = inet_ntop(prefix->family, &prefix->add.sin6, buff, INET6_ADDRSTRLEN);
97
+ assert(dst && "corrupt address");
98
+ if (with_len)
99
+ sprintf(buff + strlen(buff), "/%u", prefix->bitlen);
100
+ return buff;
206
101
  }
207
102
 
208
103
  /* prefix_toa2
@@ -214,57 +109,36 @@ prefix_toa2 (prefix_t *prefix, char *buff)
214
109
  return (prefix_toa2x (prefix, buff, 0));
215
110
  }
216
111
 
217
- /* prefix_toa
218
- */
219
- char *
220
- prefix_toa (prefix_t * prefix)
221
- {
222
- return (prefix_toa2 (prefix, (char *) NULL));
223
- }
224
-
225
112
  prefix_t *
226
113
  New_Prefix2 (int family, void *dest, int bitlen, prefix_t *prefix)
227
114
  {
228
- int dynamic_allocated = 0;
229
- int default_bitlen = 32;
230
-
231
- #ifdef HAVE_IPV6
232
- if (family == AF_INET6) {
233
- default_bitlen = 128;
234
- if (prefix == NULL) {
235
- prefix = calloc(1, sizeof (prefix6_t));
236
- dynamic_allocated++;
237
- }
238
- memcpy (&prefix->add.sin6, dest, 16);
239
- }
240
- else
241
- #endif /* HAVE_IPV6 */
242
- if (family == AF_INET) {
243
- if (prefix == NULL) {
244
- #ifndef NT
245
- prefix = calloc(1, sizeof (prefix4_t));
246
- #else
247
- //for some reason, compiler is getting
248
- //prefix4_t size incorrect on NT
249
- prefix = calloc(1, sizeof (prefix_t));
250
- #endif /* NT */
251
-
252
- dynamic_allocated++;
253
- }
254
- memcpy (&prefix->add.sin, dest, 4);
255
- }
256
- else {
257
- return (NULL);
258
- }
259
-
260
- prefix->bitlen = (bitlen >= 0)? bitlen: default_bitlen;
115
+ prefix_t *orig_prefix = prefix;
116
+ int default_bitlen;
117
+ size_t size, addr_size;
118
+
119
+ switch (family) {
120
+ case AF_INET6:
121
+ addr_size = sizeof(struct in6_addr);
122
+ size = sizeof(prefix_t);
123
+ break;
124
+ case AF_INET:
125
+ addr_size = sizeof(struct in_addr);
126
+ size = sizeof(prefix4_t);
127
+ break;
128
+ default:
129
+ return NULL;
130
+ }
131
+ default_bitlen = addr_size * CHAR_BIT;
132
+ if (bitlen > default_bitlen)
133
+ return NULL;
134
+ if (!orig_prefix)
135
+ prefix = calloc(1, size);
136
+ prefix->bitlen = bitlen >= 0 ? bitlen : default_bitlen;
261
137
  prefix->family = family;
262
- prefix->ref_count = 0;
263
- if (dynamic_allocated) {
264
- prefix->ref_count++;
265
- }
266
- /* fprintf(stderr, "[C %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */
267
- return (prefix);
138
+ prefix->ref_count = orig_prefix ? 0 : 1;
139
+ memcpy(&prefix->add.sin6, dest, addr_size);
140
+
141
+ return prefix;
268
142
  }
269
143
 
270
144
  prefix_t *
@@ -276,76 +150,46 @@ New_Prefix (int family, void *dest, int bitlen)
276
150
  /* ascii2prefix
277
151
  */
278
152
  prefix_t *
279
- ascii2prefix (int family, char *string)
153
+ ascii2prefix(char *string, prefix_t *prefix)
280
154
  {
281
- u_long bitlen, maxbitlen = 0;
282
- char *cp;
283
- struct in_addr sin;
284
- #ifdef HAVE_IPV6
285
- struct in6_addr sin6;
286
- #endif /* HAVE_IPV6 */
155
+ long bitlen;
156
+ size_t maxbitlen;
157
+ void *dest;
158
+ char *slash, *end;
287
159
  int result;
288
- char save[MAXLINE];
289
-
290
- if (string == NULL)
291
- return (NULL);
292
-
293
- /* easy way to handle both families */
294
- if (family == 0) {
295
- family = AF_INET;
296
- #ifdef HAVE_IPV6
297
- if (strchr (string, ':')) family = AF_INET6;
298
- #endif /* HAVE_IPV6 */
160
+ char save[INET6_ADDRSTRLEN];
161
+ size_t len;
162
+ int family;
163
+ union {
164
+ struct in6_addr sin6;
165
+ struct in_addr sin;
166
+ } addr;
167
+
168
+ assert(string && "string is NULL");
169
+ len = strlen(string);
170
+ slash = memchr(string, '/', len);
171
+ if (slash) {
172
+ bitlen = strtol(slash + 1, &end, 10);
173
+ if (*end || (bitlen < 0) || ((slash - string) >= (int)sizeof(save)))
174
+ return NULL;
175
+
176
+ /* copy the string to save. Avoid destroying the string */
177
+ memcpy(save, string, slash - string);
178
+ save[slash - string] = '\0';
179
+ string = save;
180
+ } else {
181
+ bitlen = -1;
299
182
  }
300
183
 
301
- if (family == AF_INET) {
302
- maxbitlen = 32;
303
- }
304
- #ifdef HAVE_IPV6
305
- else if (family == AF_INET6) {
306
- maxbitlen = 128;
307
- }
308
- #endif /* HAVE_IPV6 */
309
-
310
- if ((cp = strchr (string, '/')) != NULL) {
311
- bitlen = atol (cp + 1);
312
- /* *cp = '\0'; */
313
- /* copy the string to save. Avoid destroying the string */
314
- assert (cp - string < MAXLINE);
315
- memcpy (save, string, cp - string);
316
- save[cp - string] = '\0';
317
- string = save;
318
- if (bitlen < 0 || bitlen > maxbitlen)
319
- bitlen = maxbitlen;
320
- }
321
- else {
322
- bitlen = maxbitlen;
323
- }
324
-
325
- if (family == AF_INET) {
326
- if ((result = my_inet_pton (AF_INET, string, &sin)) <= 0)
327
- return (NULL);
328
- return (New_Prefix (AF_INET, &sin, bitlen));
329
- }
330
-
331
- #ifdef HAVE_IPV6
332
- else if (family == AF_INET6) {
333
- // Get rid of this with next IPv6 upgrade
334
- #if defined(NT) && !defined(HAVE_INET_NTOP)
335
- inet6_addr(string, &sin6);
336
- return (New_Prefix (AF_INET6, &sin6, bitlen));
337
- #else
338
- if ((result = inet_pton (AF_INET6, string, &sin6)) <= 0)
339
- return (NULL);
340
- #endif /* NT */
341
- return (New_Prefix (AF_INET6, &sin6, bitlen));
342
- }
343
- #endif /* HAVE_IPV6 */
344
- else
345
- return (NULL);
184
+ family = memchr(string, ':', len) ? AF_INET6 : AF_INET;
185
+ result = inet_pton(family, string, &addr);
186
+ if (result != 1)
187
+ return NULL;
188
+
189
+ return New_Prefix2(family, &addr, bitlen, prefix);
346
190
  }
347
191
 
348
- prefix_t *
192
+ static prefix_t *
349
193
  Ref_Prefix (prefix_t * prefix)
350
194
  {
351
195
  if (prefix == NULL)
@@ -355,11 +199,10 @@ Ref_Prefix (prefix_t * prefix)
355
199
  return (New_Prefix2 (prefix->family, &prefix->add, prefix->bitlen, NULL));
356
200
  }
357
201
  prefix->ref_count++;
358
- /* fprintf(stderr, "[A %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */
359
202
  return (prefix);
360
203
  }
361
204
 
362
- void
205
+ static void
363
206
  Deref_Prefix (prefix_t * prefix)
364
207
  {
365
208
  if (prefix == NULL)
@@ -377,8 +220,6 @@ Deref_Prefix (prefix_t * prefix)
377
220
 
378
221
  /* } */
379
222
 
380
- /* #define PATRICIA_DEBUG 1 */
381
-
382
223
  static int num_active_patricia = 0;
383
224
 
384
225
  /* these routines support continuous mask only */
@@ -512,27 +353,10 @@ patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix)
512
353
  bitlen = prefix->bitlen;
513
354
 
514
355
  while (node->bit < bitlen) {
515
-
516
356
  if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
517
- #ifdef PATRICIA_DEBUG
518
- if (node->prefix)
519
- fprintf (stderr, "patricia_search_exact: take right %s/%d\n",
520
- prefix_toa (node->prefix), node->prefix->bitlen);
521
- else
522
- fprintf (stderr, "patricia_search_exact: take right at %d\n",
523
- node->bit);
524
- #endif /* PATRICIA_DEBUG */
525
357
  node = node->r;
526
358
  }
527
359
  else {
528
- #ifdef PATRICIA_DEBUG
529
- if (node->prefix)
530
- fprintf (stderr, "patricia_search_exact: take left %s/%d\n",
531
- prefix_toa (node->prefix), node->prefix->bitlen);
532
- else
533
- fprintf (stderr, "patricia_search_exact: take left at %d\n",
534
- node->bit);
535
- #endif /* PATRICIA_DEBUG */
536
360
  node = node->l;
537
361
  }
538
362
 
@@ -540,23 +364,12 @@ patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix)
540
364
  return (NULL);
541
365
  }
542
366
 
543
- #ifdef PATRICIA_DEBUG
544
- if (node->prefix)
545
- fprintf (stderr, "patricia_search_exact: stop at %s/%d\n",
546
- prefix_toa (node->prefix), node->prefix->bitlen);
547
- else
548
- fprintf (stderr, "patricia_search_exact: stop at %d\n", node->bit);
549
- #endif /* PATRICIA_DEBUG */
550
367
  if (node->bit > bitlen || node->prefix == NULL)
551
368
  return (NULL);
552
369
  assert (node->bit == bitlen);
553
370
  assert (node->bit == node->prefix->bitlen);
554
371
  if (comp_with_mask (prefix_tochar (node->prefix), prefix_tochar (prefix),
555
372
  bitlen)) {
556
- #ifdef PATRICIA_DEBUG
557
- fprintf (stderr, "patricia_search_exact: found %s/%d\n",
558
- prefix_toa (node->prefix), node->prefix->bitlen);
559
- #endif /* PATRICIA_DEBUG */
560
373
  return (node);
561
374
  }
562
375
  return (NULL);
@@ -587,33 +400,13 @@ patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, int inclusiv
587
400
  while (node->bit < bitlen) {
588
401
 
589
402
  if (node->prefix) {
590
- #ifdef PATRICIA_DEBUG
591
- fprintf (stderr, "patricia_search_best: push %s/%d\n",
592
- prefix_toa (node->prefix), node->prefix->bitlen);
593
- #endif /* PATRICIA_DEBUG */
594
403
  stack[cnt++] = node;
595
404
  }
596
405
 
597
406
  if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
598
- #ifdef PATRICIA_DEBUG
599
- if (node->prefix)
600
- fprintf (stderr, "patricia_search_best: take right %s/%d\n",
601
- prefix_toa (node->prefix), node->prefix->bitlen);
602
- else
603
- fprintf (stderr, "patricia_search_best: take right at %d\n",
604
- node->bit);
605
- #endif /* PATRICIA_DEBUG */
606
407
  node = node->r;
607
408
  }
608
409
  else {
609
- #ifdef PATRICIA_DEBUG
610
- if (node->prefix)
611
- fprintf (stderr, "patricia_search_best: take left %s/%d\n",
612
- prefix_toa (node->prefix), node->prefix->bitlen);
613
- else
614
- fprintf (stderr, "patricia_search_best: take left at %d\n",
615
- node->bit);
616
- #endif /* PATRICIA_DEBUG */
617
410
  node = node->l;
618
411
  }
619
412
 
@@ -624,32 +417,14 @@ patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, int inclusiv
624
417
  if (inclusive && node && node->prefix)
625
418
  stack[cnt++] = node;
626
419
 
627
- #ifdef PATRICIA_DEBUG
628
- if (node == NULL)
629
- fprintf (stderr, "patricia_search_best: stop at null\n");
630
- else if (node->prefix)
631
- fprintf (stderr, "patricia_search_best: stop at %s/%d\n",
632
- prefix_toa (node->prefix), node->prefix->bitlen);
633
- else
634
- fprintf (stderr, "patricia_search_best: stop at %d\n", node->bit);
635
- #endif /* PATRICIA_DEBUG */
636
-
637
420
  if (cnt <= 0)
638
421
  return (NULL);
639
422
 
640
423
  while (--cnt >= 0) {
641
424
  node = stack[cnt];
642
- #ifdef PATRICIA_DEBUG
643
- fprintf (stderr, "patricia_search_best: pop %s/%d\n",
644
- prefix_toa (node->prefix), node->prefix->bitlen);
645
- #endif /* PATRICIA_DEBUG */
646
425
  if (comp_with_mask (prefix_tochar (node->prefix),
647
426
  prefix_tochar (prefix),
648
427
  node->prefix->bitlen)) {
649
- #ifdef PATRICIA_DEBUG
650
- fprintf (stderr, "patricia_search_best: found %s/%d\n",
651
- prefix_toa (node->prefix), node->prefix->bitlen);
652
- #endif /* PATRICIA_DEBUG */
653
428
  return (node);
654
429
  }
655
430
  }
@@ -684,10 +459,6 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
684
459
  node->l = node->r = NULL;
685
460
  node->data = NULL;
686
461
  patricia->head = node;
687
- #ifdef PATRICIA_DEBUG
688
- fprintf (stderr, "patricia_lookup: new_node #0 %s/%d (head)\n",
689
- prefix_toa (prefix), prefix->bitlen);
690
- #endif /* PATRICIA_DEBUG */
691
462
  patricia->num_active_node++;
692
463
  return (node);
693
464
  }
@@ -702,25 +473,11 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
702
473
  BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
703
474
  if (node->r == NULL)
704
475
  break;
705
- #ifdef PATRICIA_DEBUG
706
- if (node->prefix)
707
- fprintf (stderr, "patricia_lookup: take right %s/%d\n",
708
- prefix_toa (node->prefix), node->prefix->bitlen);
709
- else
710
- fprintf (stderr, "patricia_lookup: take right at %d\n", node->bit);
711
- #endif /* PATRICIA_DEBUG */
712
476
  node = node->r;
713
477
  }
714
478
  else {
715
479
  if (node->l == NULL)
716
480
  break;
717
- #ifdef PATRICIA_DEBUG
718
- if (node->prefix)
719
- fprintf (stderr, "patricia_lookup: take left %s/%d\n",
720
- prefix_toa (node->prefix), node->prefix->bitlen);
721
- else
722
- fprintf (stderr, "patricia_lookup: take left at %d\n", node->bit);
723
- #endif /* PATRICIA_DEBUG */
724
481
  node = node->l;
725
482
  }
726
483
 
@@ -728,16 +485,12 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
728
485
  }
729
486
 
730
487
  assert (node->prefix);
731
- #ifdef PATRICIA_DEBUG
732
- fprintf (stderr, "patricia_lookup: stop at %s/%d\n",
733
- prefix_toa (node->prefix), node->prefix->bitlen);
734
- #endif /* PATRICIA_DEBUG */
735
488
 
736
489
  test_addr = prefix_touchar (node->prefix);
737
490
  /* find the first bit different */
738
491
  check_bit = (node->bit < bitlen)? node->bit: bitlen;
739
492
  differ_bit = 0;
740
- for (i = 0; i*8 < check_bit; i++) {
493
+ for (i = 0; i*8 < (int)check_bit; i++) {
741
494
  if ((r = (addr[i] ^ test_addr[i])) == 0) {
742
495
  differ_bit = (i + 1) * 8;
743
496
  continue;
@@ -754,36 +507,18 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
754
507
  }
755
508
  if (differ_bit > check_bit)
756
509
  differ_bit = check_bit;
757
- #ifdef PATRICIA_DEBUG
758
- fprintf (stderr, "patricia_lookup: differ_bit %d\n", differ_bit);
759
- #endif /* PATRICIA_DEBUG */
760
510
 
761
511
  parent = node->parent;
762
512
  while (parent && parent->bit >= differ_bit) {
763
513
  node = parent;
764
514
  parent = node->parent;
765
- #ifdef PATRICIA_DEBUG
766
- if (node->prefix)
767
- fprintf (stderr, "patricia_lookup: up to %s/%d\n",
768
- prefix_toa (node->prefix), node->prefix->bitlen);
769
- else
770
- fprintf (stderr, "patricia_lookup: up to %d\n", node->bit);
771
- #endif /* PATRICIA_DEBUG */
772
515
  }
773
516
 
774
517
  if (differ_bit == bitlen && node->bit == bitlen) {
775
518
  if (node->prefix) {
776
- #ifdef PATRICIA_DEBUG
777
- fprintf (stderr, "patricia_lookup: found %s/%d\n",
778
- prefix_toa (node->prefix), node->prefix->bitlen);
779
- #endif /* PATRICIA_DEBUG */
780
519
  return (node);
781
520
  }
782
521
  node->prefix = Ref_Prefix (prefix);
783
- #ifdef PATRICIA_DEBUG
784
- fprintf (stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n",
785
- prefix_toa (prefix), prefix->bitlen);
786
- #endif /* PATRICIA_DEBUG */
787
522
  assert (node->data == NULL);
788
523
  return (node);
789
524
  }
@@ -807,10 +542,6 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
807
542
  assert (node->l == NULL);
808
543
  node->l = new_node;
809
544
  }
810
- #ifdef PATRICIA_DEBUG
811
- fprintf (stderr, "patricia_lookup: new_node #2 %s/%d (child)\n",
812
- prefix_toa (prefix), prefix->bitlen);
813
- #endif /* PATRICIA_DEBUG */
814
545
  return (new_node);
815
546
  }
816
547
 
@@ -834,10 +565,6 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
834
565
  node->parent->l = new_node;
835
566
  }
836
567
  node->parent = new_node;
837
- #ifdef PATRICIA_DEBUG
838
- fprintf (stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n",
839
- prefix_toa (prefix), prefix->bitlen);
840
- #endif /* PATRICIA_DEBUG */
841
568
  }
842
569
  else {
843
570
  glue = calloc(1, sizeof *glue);
@@ -868,10 +595,6 @@ patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix)
868
595
  node->parent->l = glue;
869
596
  }
870
597
  node->parent = glue;
871
- #ifdef PATRICIA_DEBUG
872
- fprintf (stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n",
873
- prefix_toa (prefix), prefix->bitlen);
874
- #endif /* PATRICIA_DEBUG */
875
598
  }
876
599
  return (new_node);
877
600
  }
@@ -886,11 +609,6 @@ patricia_remove (patricia_tree_t *patricia, patricia_node_t *node)
886
609
  assert (node);
887
610
 
888
611
  if (node->r && node->l) {
889
- #ifdef PATRICIA_DEBUG
890
- fprintf (stderr, "patricia_remove: #0 %s/%d (r & l)\n",
891
- prefix_toa (node->prefix), node->prefix->bitlen);
892
- #endif /* PATRICIA_DEBUG */
893
-
894
612
  /* this might be a placeholder node -- have to check and make sure
895
613
  * there is a prefix aossciated with it ! */
896
614
  if (node->prefix != NULL)
@@ -902,10 +620,6 @@ patricia_remove (patricia_tree_t *patricia, patricia_node_t *node)
902
620
  }
903
621
 
904
622
  if (node->r == NULL && node->l == NULL) {
905
- #ifdef PATRICIA_DEBUG
906
- fprintf (stderr, "patricia_remove: #1 %s/%d (!r & !l)\n",
907
- prefix_toa (node->prefix), node->prefix->bitlen);
908
- #endif /* PATRICIA_DEBUG */
909
623
  parent = node->parent;
910
624
  Deref_Prefix (node->prefix);
911
625
  Delete (node);
@@ -949,10 +663,6 @@ patricia_remove (patricia_tree_t *patricia, patricia_node_t *node)
949
663
  return;
950
664
  }
951
665
 
952
- #ifdef PATRICIA_DEBUG
953
- fprintf (stderr, "patricia_remove: #2 %s/%d (r ^ l)\n",
954
- prefix_toa (node->prefix), node->prefix->bitlen);
955
- #endif /* PATRICIA_DEBUG */
956
666
  if (node->r) {
957
667
  child = node->r;
958
668
  }
@@ -981,64 +691,3 @@ patricia_remove (patricia_tree_t *patricia, patricia_node_t *node)
981
691
  parent->l = child;
982
692
  }
983
693
  }
984
-
985
- /* { from demo.c */
986
-
987
- patricia_node_t *
988
- make_and_lookup (patricia_tree_t *tree, char *string)
989
- {
990
- prefix_t *prefix;
991
- patricia_node_t *node;
992
-
993
- prefix = ascii2prefix (AF_INET, string);
994
- printf ("make_and_lookup: %s/%d\n", prefix_toa (prefix), prefix->bitlen);
995
- node = patricia_lookup (tree, prefix);
996
- Deref_Prefix (prefix);
997
- return (node);
998
- }
999
-
1000
- patricia_node_t *
1001
- try_search_exact (patricia_tree_t *tree, char *string)
1002
- {
1003
- prefix_t *prefix;
1004
- patricia_node_t *node;
1005
-
1006
- prefix = ascii2prefix (AF_INET, string);
1007
- printf ("try_search_exact: %s/%d\n", prefix_toa (prefix), prefix->bitlen);
1008
- if ((node = patricia_search_exact (tree, prefix)) == NULL) {
1009
- printf ("try_search_exact: not found\n");
1010
- }
1011
- else {
1012
- printf ("try_search_exact: %s/%d found\n",
1013
- prefix_toa (node->prefix), node->prefix->bitlen);
1014
- }
1015
- Deref_Prefix (prefix);
1016
- return (node);
1017
- }
1018
-
1019
- void
1020
- lookup_then_remove (patricia_tree_t *tree, char *string)
1021
- {
1022
- patricia_node_t *node;
1023
-
1024
- if (node = try_search_exact (tree, string))
1025
- patricia_remove (tree, node);
1026
- }
1027
-
1028
- patricia_node_t *
1029
- try_search_best (patricia_tree_t *tree, char *string)
1030
- {
1031
- prefix_t *prefix;
1032
- patricia_node_t *node;
1033
-
1034
- prefix = ascii2prefix (AF_INET, string);
1035
- printf ("try_search_best: %s/%d\n", prefix_toa (prefix), prefix->bitlen);
1036
- if ((node = patricia_search_best (tree, prefix)) == NULL)
1037
- printf ("try_search_best: not found\n");
1038
- else
1039
- printf ("try_search_best: %s/%d found\n",
1040
- prefix_toa (node->prefix), node->prefix->bitlen);
1041
- Deref_Prefix (prefix);
1042
- }
1043
-
1044
- /* } */
@@ -23,8 +23,6 @@ typedef void (*void_fn_t)();
23
23
  #define BIT_TEST(f, b) ((f) & (b))
24
24
  /* } */
25
25
 
26
- #define addroute make_and_lookup
27
-
28
26
  #include <sys/types.h> /* for u_* definitions (on FreeBSD 5) */
29
27
 
30
28
  #include <errno.h> /* for EAFNOSUPPORT */
@@ -52,9 +50,7 @@ typedef struct _prefix_t {
52
50
  int ref_count; /* reference count */
53
51
  union {
54
52
  struct in_addr sin;
55
- #ifdef HAVE_IPV6
56
53
  struct in6_addr sin6;
57
- #endif /* IPV6 */
58
54
  } add;
59
55
  } prefix_t;
60
56
 
@@ -90,14 +86,12 @@ void patricia_process (patricia_tree_t *patricia, void_fn_t func);
90
86
  /* { from demo.c */
91
87
 
92
88
  prefix_t *
93
- ascii2prefix (int family, char *string);
94
-
95
- patricia_node_t *
96
- make_and_lookup (patricia_tree_t *tree, char *string);
89
+ ascii2prefix (char *string, prefix_t *prefix);
97
90
 
98
91
  /* } */
99
92
 
100
93
  #define PATRICIA_MAXBITS 128
94
+ #define PATRICIA_MAXSTRLEN (INET6_ADDRSTRLEN + sizeof("/128") - 1)
101
95
  #define PATRICIA_NBIT(x) (0x80 >> ((x) & 0x7f))
102
96
  #define PATRICIA_NBYTE(x) ((x) >> 3)
103
97
 
@@ -8,7 +8,12 @@
8
8
  #include "patricia.h"
9
9
  #include <assert.h>
10
10
 
11
+ size_t patricia_walk_inorder(patricia_node_t *node, void_fn_t func);
12
+ char * prefix_toa2x(prefix_t *prefix, char *buff, int with_len);
13
+ char * prefix_toa2(prefix_t *prefix, char *buff);
14
+
11
15
  static VALUE cPatricia, cNode;
16
+ static VALUE sym_AF_INET, sym_AF_INET6;
12
17
 
13
18
  static void dummy(void) {}
14
19
 
@@ -42,16 +47,18 @@ wrap_node(patricia_node_t *orig)
42
47
  return Data_Wrap_Struct(cNode, p_node_mark, -1, node);
43
48
  }
44
49
 
45
- static prefix_t *
46
- my_ascii2prefix(int family, VALUE str)
50
+ static void
51
+ my_ascii2prefix(patricia_tree_t *tree, VALUE str, prefix_t *prefix)
47
52
  {
48
- char *cstr = StringValuePtr(str);
49
- prefix_t *prefix = ascii2prefix(family, cstr);
53
+ char *cstr = StringValueCStr(str);
54
+ prefix_t *ok = ascii2prefix(cstr, prefix);
50
55
 
51
- if (!prefix)
56
+ if (!ok)
52
57
  rb_raise(rb_eArgError, "invalid prefix: %s", cstr);
53
58
 
54
- return prefix;
59
+ if (prefix->bitlen > tree->maxbits)
60
+ rb_raise(rb_eArgError, "prefix length (%u) larger than maxbits (%u)",
61
+ prefix->bitlen, tree->maxbits);
55
62
  }
56
63
 
57
64
  static VALUE
@@ -60,15 +67,14 @@ p_add (int argc, VALUE *argv, VALUE self)
60
67
  VALUE user_data;
61
68
  patricia_tree_t *tree;
62
69
  patricia_node_t *node;
63
- prefix_t *prefix;
70
+ prefix_t prefix;
64
71
 
65
72
  if (argc > 2 || argc < 1)
66
73
  return Qnil;
67
74
 
68
75
  Data_Get_Struct(self, patricia_tree_t, tree);
69
- prefix = my_ascii2prefix(AF_INET, argv[0]);
70
- node = patricia_lookup(tree, prefix);
71
- Deref_Prefix(prefix);
76
+ my_ascii2prefix(tree, argv[0], &prefix);
77
+ node = patricia_lookup(tree, &prefix);
72
78
 
73
79
  if (argc == 2) {
74
80
  user_data = argv[1];
@@ -90,12 +96,11 @@ p_remove (VALUE self, VALUE r_key)
90
96
  {
91
97
  patricia_tree_t *tree;
92
98
  patricia_node_t *node;
93
- prefix_t *prefix;
99
+ prefix_t prefix;
94
100
 
95
101
  Data_Get_Struct(self, patricia_tree_t, tree);
96
- prefix = my_ascii2prefix (AF_INET, r_key);
97
- node = patricia_search_exact(tree, prefix);
98
- Deref_Prefix (prefix);
102
+ my_ascii2prefix(tree, r_key, &prefix);
103
+ node = patricia_search_exact(tree, &prefix);
99
104
 
100
105
  if (node) {
101
106
  patricia_remove (tree, node);
@@ -110,12 +115,11 @@ p_match (VALUE self, VALUE r_key)
110
115
  {
111
116
  patricia_tree_t *tree;
112
117
  patricia_node_t *node;
113
- prefix_t *prefix;
118
+ prefix_t prefix;
114
119
 
115
120
  Data_Get_Struct(self, patricia_tree_t, tree);
116
- prefix = my_ascii2prefix (AF_INET, r_key);
117
- node = patricia_search_best(tree, prefix);
118
- Deref_Prefix (prefix);
121
+ my_ascii2prefix(tree, r_key, &prefix);
122
+ node = patricia_search_best(tree, &prefix);
119
123
 
120
124
  return node ? wrap_node(node) : Qnil;
121
125
  }
@@ -125,12 +129,11 @@ p_include (VALUE self, VALUE r_key)
125
129
  {
126
130
  patricia_tree_t *tree;
127
131
  patricia_node_t *node;
128
- prefix_t *prefix;
132
+ prefix_t prefix;
129
133
 
130
134
  Data_Get_Struct(self, patricia_tree_t, tree);
131
- prefix = my_ascii2prefix (AF_INET, r_key);
132
- node = patricia_search_best(tree, prefix);
133
- Deref_Prefix (prefix);
135
+ my_ascii2prefix(tree, r_key, &prefix);
136
+ node = patricia_search_best(tree, &prefix);
134
137
 
135
138
  return node ? Qtrue : Qfalse;
136
139
  }
@@ -140,12 +143,11 @@ p_match_exact (VALUE self, VALUE r_key)
140
143
  {
141
144
  patricia_tree_t *tree;
142
145
  patricia_node_t *node;
143
- prefix_t *prefix;
146
+ prefix_t prefix;
144
147
 
145
148
  Data_Get_Struct(self, patricia_tree_t, tree);
146
- prefix = my_ascii2prefix (AF_INET, r_key);
147
- node = patricia_search_exact(tree, prefix);
148
- Deref_Prefix (prefix);
149
+ my_ascii2prefix(tree, r_key, &prefix);
150
+ node = patricia_search_exact(tree, &prefix);
149
151
 
150
152
  return node ? wrap_node(node) : Qnil;
151
153
  }
@@ -177,7 +179,7 @@ p_print_nodes (int argc, VALUE *argv, VALUE self)
177
179
  {
178
180
  ID id_printf = rb_intern("printf");
179
181
  VALUE fmt = rb_str_new2("node: %s\n");
180
- VALUE buf = rb_str_buf_new(128);
182
+ VALUE buf = rb_str_new(0, 0);
181
183
  char *cbuf;
182
184
  patricia_tree_t *tree;
183
185
  patricia_node_t *node;
@@ -190,7 +192,7 @@ p_print_nodes (int argc, VALUE *argv, VALUE self)
190
192
 
191
193
  if (tree->head) {
192
194
  PATRICIA_WALK(tree->head, node) {
193
- rb_str_resize(buf, 128);
195
+ rb_str_resize(buf, PATRICIA_MAXSTRLEN);
194
196
  cbuf = RSTRING_PTR(buf);
195
197
  prefix_toa2x(node->prefix, cbuf, 1);
196
198
  rb_str_set_len(buf, strlen(cbuf));
@@ -219,21 +221,29 @@ p_data (VALUE self)
219
221
  static VALUE
220
222
  p_network (VALUE self)
221
223
  {
222
- char buff[32];
223
224
  patricia_node_t *node;
225
+ VALUE str = rb_str_new(0, PATRICIA_MAXSTRLEN);
226
+ char *cstr = RSTRING_PTR(str);
227
+
224
228
  Data_Get_Struct(self, patricia_node_t, node);
225
- prefix_toa2x (node->prefix, buff, 0);
226
- return rb_str_new2(buff);
229
+ prefix_toa2x(node->prefix, cstr, 0);
230
+ rb_str_set_len(str, strlen(cstr));
231
+
232
+ return str;
227
233
  }
228
234
 
229
235
  static VALUE
230
236
  p_prefix (VALUE self)
231
237
  {
232
- char buff[32];
233
238
  patricia_node_t *node;
239
+ VALUE str = rb_str_new(0, INET6_ADDRSTRLEN);
240
+ char *cstr = RSTRING_PTR(str);
241
+
234
242
  Data_Get_Struct(self, patricia_node_t, node);
235
- prefix_toa2 (node->prefix, buff);
236
- return rb_str_new2(buff);
243
+ prefix_toa2(node->prefix, cstr);
244
+ rb_str_set_len(str, strlen(cstr));
245
+
246
+ return str;
237
247
  }
238
248
 
239
249
  static VALUE
@@ -258,25 +268,42 @@ p_tree_mark (void *ptr)
258
268
  {
259
269
  patricia_tree_t *tree = ptr;
260
270
 
261
- patricia_process(tree, p_tree_mark_each);
271
+ if (tree)
272
+ patricia_process(tree, p_tree_mark_each);
262
273
  }
263
274
 
264
275
  static void
265
276
  p_tree_free (void *ptr)
266
277
  {
267
278
  patricia_tree_t *tree = ptr;
268
-
269
279
  /* no need to explicitly free each node->data, GC will do it for us */
270
- Destroy_Patricia(tree, NULL);
280
+ if (tree)
281
+ Destroy_Patricia(tree, NULL);
271
282
  }
272
283
 
273
284
  static VALUE
274
285
  p_alloc(VALUE klass)
275
286
  {
276
- patricia_tree_t *tree;
277
- tree = New_Patricia(32); /* assuming only IPv4 */
287
+ return Data_Wrap_Struct(klass, p_tree_mark, p_tree_free, NULL);
288
+ }
289
+
290
+ static VALUE
291
+ p_init(int argc, VALUE *argv, VALUE self)
292
+ {
293
+ VALUE family;
294
+ int maxbits;
295
+
296
+ rb_scan_args(argc, argv, "01", &family);
278
297
 
279
- return Data_Wrap_Struct(klass, p_tree_mark, p_tree_free, tree);
298
+ if (NIL_P(family) || family == sym_AF_INET)
299
+ maxbits = 32;
300
+ else if (family == sym_AF_INET6)
301
+ maxbits = 128;
302
+ else
303
+ rb_raise(rb_eArgError, "unknown family (must be :AF_INET6 or :AF_INET)");
304
+
305
+ DATA_PTR(self) = New_Patricia(maxbits);
306
+ return self;
280
307
  }
281
308
 
282
309
  static VALUE
@@ -288,10 +315,10 @@ p_init_copy(VALUE self, VALUE orig)
288
315
  if (orig_tree->head) {
289
316
  patricia_tree_t *tree;
290
317
  patricia_node_t *orig_node, *node;
291
- prefix_t prefix;
292
318
  VALUE user_data;
293
319
 
294
- Data_Get_Struct(self, patricia_tree_t, tree);
320
+ DATA_PTR(self) = tree = New_Patricia(orig_tree->maxbits);
321
+
295
322
  PATRICIA_WALK(orig_tree->head, orig_node) {
296
323
  node = patricia_lookup(tree, orig_node->prefix);
297
324
  assert(node->prefix == orig_node->prefix);
@@ -302,6 +329,23 @@ p_init_copy(VALUE self, VALUE orig)
302
329
  PATRICIA_DATA_SET(node, user_data);
303
330
  } PATRICIA_WALK_END;
304
331
  }
332
+
333
+ return self;
334
+ }
335
+
336
+ static VALUE
337
+ p_family(VALUE self)
338
+ {
339
+ patricia_tree_t *tree;
340
+
341
+ Data_Get_Struct(self, patricia_tree_t, tree);
342
+
343
+ switch (tree->maxbits) {
344
+ case 32: return sym_AF_INET;
345
+ case 128: return sym_AF_INET6;
346
+ }
347
+ assert(0 && "unknown maxbits, corrupt tree");
348
+ return Qnil;
305
349
  }
306
350
 
307
351
  void
@@ -309,15 +353,19 @@ Init_rpatricia (void)
309
353
  {
310
354
  cPatricia = rb_define_class("Patricia", rb_cObject);
311
355
  cNode = rb_define_class_under(cPatricia, "Node", rb_cObject);
356
+ sym_AF_INET = ID2SYM(rb_intern("AF_INET"));
357
+ sym_AF_INET6 = ID2SYM(rb_intern("AF_INET6"));
312
358
 
313
359
  /* allocate new Patricia object, called before initialize */
314
360
  rb_define_alloc_func(cPatricia, p_alloc);
361
+ rb_define_private_method(cPatricia, "initialize", p_init, -1);
315
362
  rb_define_method(cPatricia, "initialize_copy", p_init_copy, 1);
316
363
 
317
364
  /*---------- methods to tree ----------*/
318
365
  /* add string */
319
366
  rb_define_method(cPatricia, "add", p_add, -1);
320
367
  rb_define_method(cPatricia, "add_node", p_add, -1);
368
+ rb_define_method(cPatricia, "family", p_family, 0);
321
369
 
322
370
  /* match prefix */
323
371
  rb_define_method(cPatricia, "match_best", p_match, 1);
@@ -348,6 +396,4 @@ Init_rpatricia (void)
348
396
  rb_define_method(cNode, "network", p_network, 0);
349
397
  rb_define_method(cNode, "prefix", p_prefix, 0);
350
398
  rb_define_method(cNode, "prefixlen", p_prefixlen, 0);
351
- // rb_define_method(cPatricia, "family", p_family, 0);
352
-
353
399
  }
data/rpatricia.gemspec CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = %q{rpatricia}
6
- s.version = %q{0.07} # remember to update Changes if this is changed
6
+ s.version = %q{0.08} # remember to update Changes if this is changed
7
7
 
8
8
  s.homepage = "http://www.goto.info.waseda.ac.jp/~tatsuya/rpatricia/"
9
9
 
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpatricia
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
5
- prerelease: false
4
+ hash: 27
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
- - 7
9
- version: "0.07"
8
+ - 8
9
+ version: "0.08"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tatsuya Mori
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-23 00:00:00 +00:00
19
- default_executable:
18
+ date: 2011-08-13 00:00:00 Z
20
19
  dependencies: []
21
20
 
22
21
  description: |-
@@ -46,7 +45,6 @@ files:
46
45
  - ext/rpatricia/rpatricia.c
47
46
  - rpatricia.gemspec
48
47
  - test.rb
49
- has_rdoc: true
50
48
  homepage: http://www.goto.info.waseda.ac.jp/~tatsuya/rpatricia/
51
49
  licenses: []
52
50
 
@@ -76,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
74
  requirements: []
77
75
 
78
76
  rubyforge_project:
79
- rubygems_version: 1.3.7
77
+ rubygems_version: 1.8.5
80
78
  signing_key:
81
79
  specification_version: 3
82
80
  summary: module for fast IP address/prefix lookups