cidrmergerb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fa2864f0fa01c1ad5efb023dd31341ae702e5bd0
4
+ data.tar.gz: 025f66ca2d5806b2b06897c6647781e81814d4cc
5
+ SHA512:
6
+ metadata.gz: 568ae27b383f662a0445f398a95b973fcf8a121896a0b0cdc1b42f60060c9879ddce7182eed7d34fd2c8708b29bd07207ced35d6dbd939156bcd13abbd0ea005
7
+ data.tar.gz: c5428103188e353dc4d164c89f25f2daa7ae45d6d5325f3b9de3f7d49464ace3ad9cad5571cfbd60bc445dd9d3167b1043026e3ff0c7a2d53e13c4c09d0bb9bd
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ ext/cidrmergerb/libcidrmerge.o
16
+ ext/cidrmergerb/libcidrmerge.so
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cidrmergerb.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Cidrmergerb
2
+
3
+ CIDR Optimize toolkit -- wrapping for Daniele's cidr optimization awesome library
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'cidrmergerb'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install cidrmergerb
20
+
21
+ ## Usage
22
+
23
+ Cidrmergerb.optimize(cidrs) #=> optimized cidrs
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ desc "clean shared library"
11
+ task :clean_library do
12
+ FileUtils.cd(File.join(File.dirname(__FILE__), 'ext/cidrmergerb'))
13
+ %x{make clean}
14
+ end
15
+
16
+ task :default => [:clean_library, :spec]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "cidrmergerb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cidrmergerb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cidrmergerb"
8
+ spec.version = Cidrmergerb::VERSION
9
+ spec.authors = ["Newell Zhu"]
10
+ spec.email = ["newell.zhu@kingaxis.com"]
11
+
12
+ spec.summary = %q{CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.}
13
+ spec.description = %q{CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.}
14
+ spec.homepage = "https://github.com/kingaxis/cidrmergerb"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "ffi", '~> 1.9', '>= 1.9.10'
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.11"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "minitest", "~> 5.0"
26
+ end
data/ffi/Makefile ADDED
@@ -0,0 +1,28 @@
1
+ #Compiler command
2
+ UNAME_S := $(shell uname -s)
3
+ ifeq ($(UNAME_S),Linux)
4
+ CC=gcc
5
+ LIBRARY_FLAGS=-shared -lc -ldl -Wl,-soname,liboptimize.so.1
6
+ endif
7
+ ifeq ($(UNAME_S),Darwin)
8
+ CC=g++
9
+ LIBRARY_FLAGS=-shared
10
+ endif
11
+
12
+ CC_FLAGS=-O3 -fPIC -g -c -Wall -W
13
+ CC_FLAGS+= -ansi -pedantic
14
+ STD_DEFINES=-D OPTIMIZED_SORT -D INLINE -D CHAR_PREFIX
15
+
16
+ all: libcidrmerge.so.1.5.3
17
+
18
+ libcidrmerge.o : libcidrmerge.c cidrmerge.h
19
+ gcc ${STD_DEFINES} ${DEBUG_DEFINES} ${CC_FLAGS} -c libcidrmerge.c
20
+
21
+ libcidrmerge.so.1.5.3 : libcidrmerge.o
22
+ ${CC} ${LIBRARY_FLAGS} -o libcidrmerge.so libcidrmerge.o
23
+
24
+ clean :
25
+ rm -f *.o core
26
+ rm -f libcidrmerge.so
27
+ rm -f timestamp.out gmon.out
28
+
data/ffi/cidrmerge.h ADDED
@@ -0,0 +1,153 @@
1
+ /*
2
+ Copyright 2004-2008 Daniele Depetrini
3
+ Author: Daniele Depetrini (depetrini@libero.it)
4
+ Version: 1.5.3
5
+ Date: 07/07/08
6
+
7
+ This file is part of cidrmerge.
8
+
9
+ CIDRMerge is free software; you can redistribute it and/or modify
10
+ it under the terms of the GNU General Public License as published by
11
+ the Free Software Foundation; either version 2 of the License, or
12
+ (at your option) any later version.
13
+
14
+ CIDRMerge is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ GNU General Public License for more details.
18
+
19
+ You should have received a copy of the GNU General Public License
20
+ along with cidrmerge; if not, write to the Free Software
21
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
+
23
+ */
24
+
25
+ #ifndef CIDRMERGE
26
+ #define CIDRMERGE
27
+
28
+ #include <stdio.h>
29
+
30
+ #ifdef UNIX_IO
31
+ #include <unistd.h>
32
+ #include <sys/types.h>
33
+ #include <sys/stat.h>
34
+ #include <fcntl.h>
35
+
36
+ #define STREAM int
37
+ #define STDIN 0
38
+ #define STDOUT 1
39
+ #define STDERR 2
40
+
41
+ #define READ(f,b,n) read(f,b,n)
42
+ #define WRITE(f,b,n) write(f,b,n)
43
+ #define OPEN(name) open(name,O_RDONLY)
44
+ #define CLOSE(f) close(f)
45
+ #define N_EOF(f,ret) (ret==0)
46
+
47
+ #else
48
+
49
+ #define STREAM FILE *
50
+ #define STDIN (stdin)
51
+ #define STDOUT (stdout)
52
+ #define STDERR (stderr)
53
+
54
+ #define READ(f,b,n) fread(b,1,n,f)
55
+ #define WRITE(f,b,n) fwrite(b,1,n,f)
56
+ #define OPEN(name) fopen(name,"r")
57
+ #define CLOSE(f) fclose(f)
58
+ #define N_EOF(f,ret) feof(f)
59
+
60
+ #endif
61
+
62
+ #ifdef TIMESTAMP
63
+ #include <sys/time.h>
64
+ #include <time.h>
65
+ #endif
66
+
67
+ #include <stdlib.h>
68
+ #include <string.h>
69
+ #include <stdint.h>
70
+
71
+ #define MAXLINE 1023
72
+ #define BUFFER 8192*8
73
+
74
+ /* Allocate BUCKET array entries per time */
75
+ #define BUCKET 100000
76
+ #define MAXCIDR 23
77
+
78
+ /*Special prefix values.
79
+ Important: INVALID_PREFIX must be < EXPANDED_PREFIX.
80
+ EXPANDED_PREFIX + 32 must be < 255
81
+ */
82
+ #define INVALID_PREFIX 200
83
+ #define EXPANDED_PREFIX 220
84
+
85
+ #define MASK1 0xff000000
86
+ #define MASK2 0xff0000
87
+ #define MASK3 0xff00
88
+ #define MASK4 0xff
89
+
90
+ #ifndef MAXINT
91
+ #define MAXINT 0xffffffff
92
+ #endif
93
+
94
+ /* timestamping precision definitions */
95
+ #define PRECISION (1000)
96
+ #define PRECISION_INV (1000000/PRECISION)
97
+ #define PRECISION_STRING "milliseconds"
98
+
99
+ struct entry
100
+ {
101
+ uint32_t network;
102
+ #ifdef CHAR_PREFIX
103
+ unsigned char prefix;
104
+ #else
105
+ uint32_t prefix;
106
+ #endif
107
+ };
108
+
109
+ static uint32_t prefix_table[]= {
110
+ 0x0,0x80000000,0xc0000000,0xe0000000,0xf0000000,0xf8000000,0xfc000000,0xfe000000,0xff000000,0xff800000,
111
+ 0xffc00000,0xffe00000,0xfff00000,0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,0xffff8000,0xffffc000,
112
+ 0xffffe000,0xfffff000,0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,0xffffff80,0xffffffc0,0xffffffe0,
113
+ 0xfffffff0,0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff
114
+ };
115
+
116
+ /*#define TONETMASK(PREFIX) (((PREFIX)==0)?(0):(MAXINT<<(32-(PREFIX))))*/
117
+ #define TONETMASK(PREFIX) prefix_table[PREFIX]
118
+
119
+ /*
120
+ Function execute the reduction of entry array addr.It returns the number of entries in the final array.
121
+ PARAM: addr array: contains entries to be optimized
122
+ PARAM: len: number of entries into addr array.
123
+ PARAM: do_sort: if 0, sort will NOT be perfomed. Be carefull: optimizing a non-sorted input will produce unpredictable results
124
+ NOTE3: resulting array may contains entries with prefix bigger than EXPANDED_PREFIX. Those are logical pointers: expanded_list[entry.network] (array returned by apply_whitelist function) is the starting position and the leght is entry.prefix- EXPANDED_PREFIX
125
+ */
126
+ unsigned int optimize(struct entry *addr,unsigned int len,int do_sort);
127
+
128
+ /*
129
+ Remove from array *entry_list occurence of array white.
130
+ Returns number of element into output array expanded_list (that can be reassigned to allow array extension).
131
+ Function allocate more memory if needed. It does NOT deallocate any if the result is smaller.
132
+ PARAM: *entry_list: pointer to input/output param entry list.
133
+ PARAM: **expanded_list: pointer to output param entry list, used to store expanded networks.
134
+ PARAM: *white: white list entry array
135
+ PARAM: len1: number of entry into entry_list in input
136
+ PARAM: len2: number of entry into white_list in input
137
+ PARAM: size_expanded: return paramether that contains memory size of the output expanded_list array
138
+ PARAM: do_sort: if 0, sort will NOT be perfomed on both entry_list and white. Be carefull: optimizing a non-sorted input will produce unpredictable results
139
+ NOTE1: both arrays entry_list and white have to be sorted with sort_entries() function BEFORE calling this.function OR paramether do_sort needs to be set to non zero. Unpredictable results if not
140
+ NOTE2: resulting array may contains entries with INVALID_PREFIX value prefix. This means entry is invalid and it doesn't have to be taken into account.
141
+ NOTE3: resulting array may contains entries with prefix bigger than EXPANDED_PREFIX. Those are logical pointers: expanded_list[entry.network] is the starting position and the leght is entry.prefix- EXPANDED_PREFIX
142
+ NOTE4: resulning array is ordered apart from invalid entries (the ones with INVALID_PREFIX value in prefix)
143
+ */
144
+ unsigned int apply_whitelist(struct entry *addr,struct entry **expanded_list,struct entry *white,unsigned int len1,unsigned int len2,unsigned int *size_expanded,int do_sort);
145
+
146
+ /*
147
+ Execute entries sorting using quicksort.
148
+ PARAM: addr array: contains entries to be sorted
149
+ PARAM: len: number of entries into addr array.
150
+ */
151
+ void sort_entries(struct entry *addr,unsigned int len);
152
+
153
+ #endif
@@ -0,0 +1,529 @@
1
+ /*
2
+ Copyright 2004-2008 Daniele Depetrini
3
+ Author: Daniele Depetrini (depetrini@libero.it)
4
+ Version: 1.5.3
5
+ Date: 06/07/08
6
+
7
+ This file is part of CIDRMerge.
8
+
9
+ CIDRMerge is free software; you can redistribute it and/or modify
10
+ it under the terms of the GNU General Public License as published by
11
+ the Free Software Foundation; either version 2 of the License, or
12
+ (at your option) any later version.
13
+
14
+ CIDRMerge is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ GNU General Public License for more details.
18
+
19
+ You should have received a copy of the GNU General Public License
20
+ along with CIDRMerge; if not, write to the Free Software
21
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
+
23
+ */
24
+
25
+ #include "cidrmerge.h"
26
+
27
+ #ifdef LIBRARY_DEBUG
28
+ #include <stdarg.h>
29
+
30
+ /* Using those functions from cidrmerge.c for debugging purposes only */
31
+ void print_address(STREAM file,uint32_t net, unsigned char pref);
32
+ void print_addresses(STREAM f,struct entry *addr,int size,struct entry *expanded,int level);
33
+
34
+ void print_debug(STREAM f,char *buf,char *fmt,...)
35
+ {
36
+ va_list ap;
37
+ va_start(ap, fmt);
38
+ sprintf(buf,fmt,ap);
39
+ WRITE(f,buf,strlen(buf));
40
+ va_end(ap);
41
+ }
42
+
43
+ #endif
44
+ /*
45
+ Exectute one entry comparation. a1 is bigger than a2 if:
46
+ - a1.network is bigger than a2.network
47
+ - a1.network is equal to a2.network but a1.prefix is bigger than a2.prefix
48
+ PARAM: a1 first entry
49
+ PARAM: a2 second entry
50
+ RETURN VALUE: it returns -1 if a1<a2, 0 if a1=a2 and 1 if a1>a2
51
+ */
52
+ #ifndef OPTIMIZED_SORT
53
+ typedef int(*cmp_type)(const void *,const void*);
54
+
55
+ static int cmp_entry(struct entry *a1, struct entry *a2)
56
+ {
57
+ if ((*a1).network<(*a2).network)
58
+ {
59
+ return -1;
60
+ }
61
+ if ((*a1).network>(*a2).network)
62
+ {
63
+ return 1;
64
+ }
65
+ /* Network are ==, so we compare netmasks*/
66
+ if ((*a1).prefix<(*a2).prefix)
67
+ {
68
+ return -1;
69
+ }
70
+ if ((*a1).prefix>(*a2).prefix)
71
+ {
72
+ return 1;
73
+ }
74
+
75
+ return 0;
76
+ }
77
+ #endif
78
+
79
+ /*
80
+ Please see cidrmerge.h
81
+ */
82
+ void sort_entries(struct entry *addr,unsigned int len)
83
+ {
84
+ #ifndef OPTIMIZED_SORT
85
+ /*standard C quicksort*/
86
+ qsort(addr,len,sizeof(struct entry),(cmp_type)cmp_entry);
87
+ #else
88
+ /*Optimized quicksort. Thanks to Michael Tokarev*/
89
+ #include "optimized-sort.h"
90
+ #define cmp_entry(a1,a2) (((a1)->network<(a2)->network) || (((a1)->network==(a2)->network) && ((a1)->prefix<(a2)->prefix)))
91
+
92
+ if (len>1)
93
+ {
94
+ /*sprintf(debug_buf,"SORT: addr[0] %d len %d\n",addr[0].network,len);*/
95
+ QSORT(struct entry,addr,len,cmp_entry);
96
+ }
97
+ #endif
98
+ }
99
+
100
+ #ifdef INLINE
101
+ __inline
102
+ #endif
103
+ static void expand(struct entry **expanded_list,struct entry to_expand,struct entry *white,unsigned int len_white,unsigned int n,unsigned int *current_position,unsigned int *size_expanded)
104
+ {
105
+ int first=*current_position,last=*current_position+n-1;
106
+ unsigned int first_conflict,last_conflict,i;
107
+ struct entry tmp_small,tmp_big;
108
+ struct entry *result=*expanded_list;
109
+ #ifdef LIBRARY_DEBUG
110
+ char debug_buf[MAXLINE];
111
+ #endif
112
+
113
+ *current_position+=n;
114
+
115
+ if (*current_position>*size_expanded)
116
+ {
117
+ /* we need to increase expanded_list array size */
118
+ #ifdef LIBRARY_DEBUG
119
+ print_debug(STDOUT,debug_buf,"BEFORE realloc: size_expanded: %u, MEM: %u\n", *size_expanded,(*size_expanded)*sizeof(struct entry));
120
+ #endif
121
+
122
+ *size_expanded+=BUCKET;
123
+ #ifdef LIBRARY_DEBUG
124
+ print_debug(STDOUT,debug_buf,"AFTER realloc size_expanded: %u,MEM: %u\n", *size_expanded,(*size_expanded)*sizeof(struct entry));
125
+ #endif
126
+
127
+ result=*expanded_list=realloc(*expanded_list,(*size_expanded)*sizeof(struct entry));
128
+ if (result==NULL)
129
+ {
130
+ fprintf(stderr,"Error reallocating %lu bytes\n",(unsigned long)(*size_expanded)*sizeof(struct entry));
131
+ exit(1);
132
+ }
133
+ }
134
+
135
+ #ifdef LIBRARY_DEBUG
136
+ print_debug(STDOUT,debug_buf,"\nTO EXPAND n %u:\n",n);
137
+ print_address(STDOUT,to_expand.network,to_expand.prefix);
138
+
139
+ print_debug(STDOUT,debug_buf,"START WHITE len_white %u:\n",len_white);
140
+ print_addresses(STDOUT,white,len_white,NULL,0);
141
+ print_debug(STDOUT,debug_buf,"END WHITE\n");
142
+ #endif
143
+
144
+ while (first<=last)
145
+ {
146
+ tmp_small.prefix=tmp_big.prefix=to_expand.prefix+1;
147
+ tmp_small.network=to_expand.network; /*last network bit set to 0 */
148
+ tmp_big.network=to_expand.network+(0x1<<(32-tmp_small.prefix)); /*last network bit set to 1 */
149
+
150
+ if ( (white[0].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network )
151
+ {
152
+ /* conflicting whith tmp_small. */
153
+ i=1;
154
+ /* search for first conflicting position with tmp_big (it cant be the first) */
155
+ while((i<len_white) && !( (white[i].network & TONETMASK(tmp_big.prefix) ) == tmp_big.network ))
156
+ {
157
+ i++;
158
+ }
159
+ first_conflict=i;
160
+ /* search for last conflicting position with tmp_big*/
161
+ while((i<len_white) && ( (white[i].network & TONETMASK(tmp_big.prefix) ) == tmp_big.network ))
162
+ {
163
+ i++;
164
+ }
165
+ last_conflict=i;
166
+ /* check if there is at least one conflicting with tmp_big network into whitelist */
167
+ if (first_conflict!=len_white)
168
+ {
169
+ if (white[first_conflict].prefix!=tmp_big.prefix)
170
+ {
171
+
172
+ #ifdef LIBRARY_DEBUG
173
+ print_debug(STDOUT,debug_buf,"RE-CONFLICT BIG first %u last %u\n",first_conflict,last_conflict);
174
+ print_address(STDOUT,tmp_big.network,tmp_big.prefix);
175
+ #endif
176
+
177
+ result[last].network=*current_position;
178
+ result[last].prefix=EXPANDED_PREFIX+white[first_conflict].prefix-tmp_big.prefix;
179
+
180
+ expand(expanded_list,tmp_big,&white[first_conflict],last_conflict-first_conflict,white[first_conflict].prefix-tmp_big.prefix,current_position,size_expanded);
181
+ }
182
+ else
183
+ {
184
+ #ifdef LIBRARY_DEBUG
185
+ print_debug(STDOUT,debug_buf,"INVALIDATING BIG POSITION %u\n",last);
186
+ #endif
187
+ result[last].prefix=INVALID_PREFIX;
188
+ }
189
+ }
190
+ else
191
+ {
192
+ #ifdef LIBRARY_DEBUG
193
+ print_debug(STDOUT,debug_buf,"VALID BIG position %u:\n",last);
194
+ print_address(STDOUT,tmp_big.network,tmp_big.prefix);
195
+ #endif
196
+ result[last].network=tmp_big.network;
197
+ result[last].prefix=tmp_big.prefix;
198
+ }
199
+ to_expand.network=tmp_small.network;
200
+ to_expand.prefix=tmp_small.prefix;
201
+ last--;
202
+ }
203
+ else
204
+ {
205
+ /* conflicting with tmp_big */
206
+ i=1;
207
+ /* search for first conflicting position with tmp_small (it cant be the first)*/
208
+ while((i<len_white) && !( (white[i].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network ))
209
+ {
210
+ i++;
211
+ }
212
+ first_conflict=i;
213
+ /* search for last conflicting position with tmp_small*/
214
+ while((i<len_white) && ( (white[i].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network ))
215
+ {
216
+ i++;
217
+ }
218
+ last_conflict=i;
219
+
220
+ /* check if there is at least one conflicting with tmp_small network into whitelist */
221
+ if (first_conflict!=len_white)
222
+ {
223
+ if (white[first_conflict].prefix!=tmp_small.prefix)
224
+ {
225
+ #ifdef LIBRARY_DEBUG
226
+ print_debug(STDOUT,debug_buf,"RE-CONFLICT LOW first %u last %u\n",first_conflict,last_conflict);
227
+ print_address(STDOUT,tmp_small.network,tmp_small.prefix);
228
+ #endif
229
+
230
+ result[first].network=*current_position;
231
+ result[first].prefix=EXPANDED_PREFIX+white[first_conflict].prefix-tmp_small.prefix;
232
+
233
+ expand(expanded_list,tmp_small,&white[first_conflict],last_conflict-first_conflict,white[first_conflict].prefix-tmp_small.prefix,current_position,size_expanded);
234
+ }
235
+ else
236
+ {
237
+ #ifdef LIBRARY_DEBUG
238
+ print_debug(STDOUT,debug_buf,"INVALIDATING LOW POSITION %u\n",first);
239
+ #endif
240
+ result[first].prefix=INVALID_PREFIX;
241
+ }
242
+ }
243
+ else
244
+ {
245
+ #ifdef LIBRARY_DEBUG
246
+ print_debug(STDOUT,debug_buf,"VALID LOW position %u:\n",first);
247
+ print_address(STDOUT,tmp_small.network,tmp_small.prefix);
248
+ #endif
249
+
250
+ result[first].network=tmp_small.network;
251
+ result[first].prefix=tmp_small.prefix;
252
+ }
253
+ to_expand.network=tmp_big.network;
254
+ to_expand.prefix=tmp_big.prefix;
255
+ first++;
256
+ }
257
+
258
+ #ifdef LIBRARY_DEBUG
259
+ print_debug(STDOUT,debug_buf,"first %d last %d\n",first,last);
260
+ #endif
261
+ }
262
+
263
+ #ifdef LIBRARY_DEBUG
264
+ print_debug(STDOUT,debug_buf,"EXPAND END. Local position %d, current position %u:\n",n,*current_position);
265
+ print_debug(STDOUT,debug_buf,"\n");
266
+ #endif
267
+ }
268
+
269
+ /*
270
+ Please see cidrmerge.h
271
+ */
272
+ unsigned int apply_whitelist(struct entry *addr,struct entry **expanded_list,struct entry *white,unsigned int len1,unsigned int len2,unsigned int *size_expanded,int do_sort)
273
+ {
274
+ unsigned int i1,i2,invalid,tmp,expanded_index=0;
275
+ uint32_t supermask;
276
+ struct entry tmp_entry;
277
+ #ifdef LIBRARY_DEBUG
278
+ char debug_buf[MAXLINE];
279
+ unsigned int step=0;
280
+ print_debug(STDOUT,debug_buf,"START apply_whitelist\n");
281
+ #endif
282
+
283
+
284
+ if (do_sort)
285
+ {
286
+ #ifdef LIBRARY_DEBUG
287
+ print_debug(STDOUT,debug_buf,"Sorting entries\n");
288
+ #endif
289
+ sort_entries(addr,len1);
290
+ sort_entries(white,len2);
291
+ }
292
+
293
+ i1=i2=0;
294
+ while ((i1<len1)&&(i2<len2))
295
+ {
296
+ #ifdef LIBRARY_DEBUG
297
+ print_debug(STDOUT,debug_buf,"STEP=%u I1=%d I2=%d\n",step++,i1,i2);
298
+ #endif
299
+ #ifdef LIBRARY_DEBUG_FULL
300
+ print_addresses(STDOUT,addr,len1,NULL,0);
301
+ #endif
302
+
303
+ supermask=TONETMASK(addr[i1].prefix)&TONETMASK(white[i2].prefix);
304
+
305
+ if ((addr[i1].prefix<=32)&&(addr[i1].network&supermask)==(white[i2].network&supermask))
306
+ {
307
+ #ifdef LIBRARY_DEBUG
308
+ print_debug(STDOUT,debug_buf,"CONFLICT\n");
309
+ print_address(STDOUT,addr[i1].network,addr[i1].prefix);
310
+ print_address(STDOUT,white[i2].network,white[i2].prefix);
311
+ #endif
312
+ if (addr[i1].prefix<white[i2].prefix)
313
+ {
314
+ /*we have to expand the network*/
315
+
316
+ /*invalidate all addr[i1] subnetworks */
317
+ invalid=i1+1;
318
+ while ((invalid<len1)&&(addr[invalid].network&supermask)==(white[i2].network&supermask))
319
+ {
320
+ /*address is already present in the expanded network, just drop it*/
321
+ #ifdef LIBRARY_DEBUG
322
+ print_debug(STDOUT,debug_buf,"INVALIDATING ");
323
+ print_address(STDOUT,addr[invalid].network,addr[invalid].prefix);
324
+ #endif
325
+ addr[invalid].prefix=INVALID_PREFIX;
326
+
327
+ invalid++;
328
+ }
329
+
330
+ invalid-=i1+1; /*invalid represents the number of invalidated positions*/
331
+
332
+ #ifdef LIBRARY_DEBUG
333
+ print_debug(STDOUT,debug_buf,"INVALID %u LEN1 %u\n",invalid,len1);
334
+ #endif
335
+
336
+ tmp=i2;
337
+ i2+=1;
338
+ while ( (i2<len2) && ((addr[i1].network&supermask)==(white[i2].network&supermask)) )
339
+ {
340
+ i2++;
341
+ }
342
+
343
+ #ifdef LIBRARY_DEBUG
344
+ print_debug(STDOUT,debug_buf,"EXPAND expanded_index %u whitelist elements: %u num expand %d\n",expanded_index,i2-tmp,white[tmp].prefix-addr[i1].prefix);
345
+ #endif
346
+
347
+ tmp_entry.network=addr[i1].network;
348
+ tmp_entry.prefix=addr[i1].prefix;
349
+
350
+ addr[i1].prefix=EXPANDED_PREFIX+white[tmp].prefix-addr[i1].prefix;
351
+ addr[i1].network=expanded_index;
352
+ /* expanded positions are clean and optimized */
353
+ expand(expanded_list,tmp_entry,&(white[tmp]),i2-tmp,white[tmp].prefix-tmp_entry.prefix,&expanded_index,size_expanded);
354
+
355
+ i1+=invalid+1;
356
+
357
+ #ifdef LIBRARY_DEBUG
358
+ print_debug(STDOUT,debug_buf,"END MAIN EXPAND expanded_index %u i1: %u i2: %u\n",expanded_index,i1,i2);
359
+ #endif
360
+
361
+ }
362
+ else
363
+ {
364
+ /*just invalidating entry i1*/
365
+ #ifdef LIBRARY_DEBUG
366
+ printf ("INVALIDATING ");
367
+ print_address(STDOUT,addr[i1].network,addr[i1].prefix);
368
+ #endif
369
+ addr[i1].prefix=INVALID_PREFIX;
370
+ i1++;
371
+ }
372
+
373
+ }
374
+ else if ((addr[i1].prefix==INVALID_PREFIX)||(addr[i1].network&supermask)<=(white[i2].network&supermask))
375
+ {
376
+ i1++;
377
+ }
378
+ else
379
+ {
380
+ i2++;
381
+ }
382
+ }
383
+ #ifdef LIBRARY_DEBUG
384
+ print_debug(STDOUT,debug_buf,"END apply_whitelist\n");
385
+ #endif
386
+ return expanded_index;
387
+ }
388
+
389
+ /*
390
+ Please see cidrmerge.h
391
+ */
392
+ unsigned int optimize(struct entry *addr,unsigned int len,int do_sort)
393
+ {
394
+ unsigned int i,cur;
395
+ unsigned int tmp_net;
396
+ #ifdef LIBRARY_DEBUG
397
+ char debug_buf[MAXLINE];
398
+ unsigned int step=0;
399
+
400
+ print_debug(STDOUT,debug_buf,"START optimize\n");
401
+ #endif
402
+
403
+ i=0; /*pointer to last valid position*/
404
+ cur=1; /*pointer to next addr to analize*/
405
+
406
+ if (len <= 1)
407
+ {
408
+ /* empty or sigle element array is optimized by definition.*/
409
+ return len;
410
+ }
411
+
412
+ if (do_sort)
413
+ {
414
+ sort_entries(addr,len);
415
+ }
416
+
417
+ /*Find first valid address and move it to first position*/
418
+ while ((addr[0].prefix==INVALID_PREFIX) && (cur<len))
419
+ {
420
+ #ifdef LIBRARY_DEBUG
421
+ printf ("SEARCH FIRST I: %d CUR: %d\n",i,cur);
422
+ #endif
423
+ if (addr[cur].prefix!=INVALID_PREFIX)
424
+ {
425
+ addr[0].network=addr[cur].network;
426
+ addr[0].prefix=addr[cur].prefix;
427
+ addr[cur].prefix=INVALID_PREFIX;
428
+ }
429
+ cur++;
430
+ }
431
+
432
+ while (cur<len)
433
+ {
434
+ #ifdef LIBRARY_DEBUG
435
+ printf ("STEP: %u I: %d CUR: %d\n",step++,i,cur);
436
+ #endif
437
+ #ifdef LIBRARY_DEBUG_FULL
438
+ print_addresses(STDOUT,addr,len,NULL,0);
439
+ #endif
440
+
441
+ /*check for expanded networks, they can never conflicts*/
442
+ if (addr[cur].prefix>=EXPANDED_PREFIX)
443
+ {
444
+ #ifdef LIBRARY_DEBUG
445
+ printf ("COPY EXPANDED I: %d CUR: %d\n",i,cur);
446
+ #endif
447
+ i++;
448
+ addr[i].network=addr[cur].network;
449
+ addr[i].prefix=addr[cur].prefix;
450
+ cur++;
451
+ while ((addr[i].prefix>=EXPANDED_PREFIX) && (cur<len))
452
+ {
453
+ #ifdef LIBRARY_DEBUG
454
+ printf ("COPY ADDR[CUR] FOR EXPANDED I: %d CUR: %d\n",i,cur);
455
+ #endif
456
+ if (addr[cur].prefix!=INVALID_PREFIX)
457
+ {
458
+ i++;
459
+ if (cur != i)
460
+ {
461
+ addr[i].network=addr[cur].network;
462
+ addr[i].prefix=addr[cur].prefix;
463
+ addr[cur].prefix=INVALID_PREFIX;
464
+ }
465
+ }
466
+ cur++;
467
+ }
468
+ }
469
+ else
470
+ {
471
+ /*If this test will fail we just skip addr[cur]*/
472
+ if ((addr[cur].prefix<=32)&&((addr[cur].network&TONETMASK(addr[i].prefix))!=addr[i].network))
473
+ {
474
+ tmp_net=TONETMASK(addr[i].prefix-1);
475
+
476
+ if ( (addr[i].prefix==addr[cur].prefix) && ( (addr[i].network&tmp_net) == (addr[cur].network&tmp_net) ) )
477
+ {
478
+ #ifdef LIBRARY_DEBUG
479
+ printf ("COLLAPSE I: %d CUR: %d\n",i,cur);
480
+ #endif
481
+
482
+ if (i>0)
483
+ {
484
+ addr[cur].prefix=addr[i].prefix-1;
485
+ addr[cur].network&=tmp_net;
486
+ i--;
487
+ }
488
+ else
489
+ {
490
+ addr[i].prefix=addr[i].prefix-1;
491
+ addr[i].network&=tmp_net;
492
+ cur++;
493
+ }
494
+ }
495
+ else
496
+ {
497
+ i++;
498
+
499
+ addr[i].network=addr[cur].network;
500
+ addr[i].prefix=addr[cur].prefix;
501
+
502
+ cur++;
503
+ }
504
+ }
505
+ else
506
+ {
507
+ #ifdef LIBRARY_DEBUG
508
+ printf ("SKIP CUR: %d\n",cur);
509
+ #endif
510
+
511
+ cur++;
512
+ }
513
+ }
514
+ }
515
+
516
+ #ifdef LIBRARY_DEBUG
517
+ print_debug(STDOUT,debug_buf,"END optimize\n");
518
+ #endif
519
+
520
+ if (addr[i].prefix!=INVALID_PREFIX)
521
+ {
522
+ return i+1;
523
+ }
524
+ else
525
+ {
526
+ return i;
527
+ }
528
+ }
529
+
@@ -0,0 +1,292 @@
1
+ /* $Id: optimized-sort.h,v 1.1 2008/06/07 22:30:24 depetrini Exp $
2
+ * Adopted from GNU glibc by Mjt.
3
+ * See stdlib/qsort.c in glibc */
4
+
5
+ /* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
6
+ This file is part of the GNU C Library.
7
+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
8
+
9
+ The GNU C Library is free software; you can redistribute it and/or
10
+ modify it under the terms of the GNU Lesser General Public
11
+ License as published by the Free Software Foundation; either
12
+ version 2.1 of the License, or (at your option) any later version.
13
+
14
+ The GNU C Library is distributed in the hope that it will be useful,
15
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
+ Lesser General Public License for more details.
18
+
19
+ You should have received a copy of the GNU Lesser General Public
20
+ License along with the GNU C Library; if not, write to the Free
21
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22
+ 02111-1307 USA. */
23
+
24
+ /* in-line qsort implementation. Differs from traditional qsort() routine
25
+ * in that it is a macro, not a function, and instead of passing an address
26
+ * of a comparision routine to the function, it is possible to inline
27
+ * comparision routine, thus speed up sorting alot.
28
+ *
29
+ * Usage:
30
+ * #include "iqsort.h"
31
+ * #define islt(a,b) (strcmp((*a),(*b))<0)
32
+ * char *arr[];
33
+ * int n;
34
+ * QSORT(char*, arr, n, islt);
35
+ *
36
+ * The "prototype" and 4 arguments are:
37
+ * QSORT(TYPE,BASE,NELT,ISLT)
38
+ * 1) type of each element, TYPE,
39
+ * 2) address of the beginning of the array, of type TYPE*,
40
+ * 3) number of elements in the array, and
41
+ * 4) comparision routine.
42
+ * Array pointer and number of elements are referenced only once.
43
+ * This is similar to a call
44
+ * qsort(BASE,NELT,sizeof(TYPE),ISLT)
45
+ * with the difference in last parameter.
46
+ * Note the islt macro/routine (it receives pointers to two elements):
47
+ * the only condition of interest is whenever one element is less than
48
+ * another, no other conditions (greather than, equal to etc) are tested.
49
+ * So, for example, to define integer sort, use:
50
+ * #define islt(a,b) ((*a)<(*b))
51
+ * QSORT(int, arr, n, islt)
52
+ *
53
+ * The macro could be used to implement a sorting function (see examples
54
+ * below), or to implement the sorting algorithm inline. That is, either
55
+ * create a sorting function and use it whenever you want to sort something,
56
+ * or use QSORT() macro directly instead a call to such routine. Note that
57
+ * the macro expands to quite some code (compiled size of int qsort on x86
58
+ * is about 700..800 bytes).
59
+ *
60
+ * Using this macro directly it isn't possible to implement traditional
61
+ * qsort() routine, because the macro assumes sizeof(element) == sizeof(TYPE),
62
+ * while qsort() allows element size to be different.
63
+ *
64
+ * Several ready-to-use examples:
65
+ *
66
+ * Sorting array of integers:
67
+ * void int_qsort(int *arr, unsigned n) {
68
+ * #define int_lt(a,b) ((*a)<(*b))
69
+ * QSORT(int, arr, n, int_lt);
70
+ * }
71
+ *
72
+ * Sorting array of string pointers:
73
+ * void str_qsort(char *arr[], unsigned n) {
74
+ * #define str_lt(a,b) (strcmp((*a),(*b)) < 0)
75
+ * QSORT(char*, arr, n, str_lt);
76
+ * }
77
+ *
78
+ * Sorting array of structures:
79
+ *
80
+ * struct elt {
81
+ * int key;
82
+ * ...
83
+ * };
84
+ * void elt_qsort(struct elt *arr, unsigned n) {
85
+ * #define elt_lt(a,b) ((a)->key < (b)->key)
86
+ * QSORT(struct elt, arr, n, elt_lt);
87
+ * }
88
+ *
89
+ * And so on.
90
+ */
91
+
92
+ /* Swap two items pointed to by A and B using temporary buffer t. */
93
+ #define _QSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t)))
94
+
95
+ /* Discontinue quicksort algorithm when partition gets below this size.
96
+ This particular magic number was chosen to work best on a Sun 4/260. */
97
+ #define _QSORT_MAX_THRESH 4
98
+
99
+ /* Stack node declarations used to store unfulfilled partition obligations
100
+ * (inlined in QSORT).
101
+ typedef struct {
102
+ QSORT_TYPE *_lo, *_hi;
103
+ } qsort_stack_node;
104
+ */
105
+
106
+ /* The next 4 #defines implement a very fast in-line stack abstraction. */
107
+ /* The stack needs log (total_elements) entries (we could even subtract
108
+ log(MAX_THRESH)). Since total_elements has type unsigned, we get as
109
+ upper bound for log (total_elements):
110
+ bits per byte (CHAR_BIT) * sizeof(unsigned). */
111
+ #define _QSORT_STACK_SIZE (8 * sizeof(unsigned))
112
+ #define _QSORT_PUSH(top, low, high) \
113
+ (((top->_lo = (low)), (top->_hi = (high)), ++top))
114
+ #define _QSORT_POP(low, high, top) \
115
+ ((--top, (low = top->_lo), (high = top->_hi)))
116
+ #define _QSORT_STACK_NOT_EMPTY (_stack < _top)
117
+
118
+
119
+ /* Order size using quicksort. This implementation incorporates
120
+ four optimizations discussed in Sedgewick:
121
+
122
+ 1. Non-recursive, using an explicit stack of pointer that store the
123
+ next array partition to sort. To save time, this maximum amount
124
+ of space required to store an array of SIZE_MAX is allocated on the
125
+ stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
126
+ only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
127
+ Pretty cheap, actually.
128
+
129
+ 2. Chose the pivot element using a median-of-three decision tree.
130
+ This reduces the probability of selecting a bad pivot value and
131
+ eliminates certain extraneous comparisons.
132
+
133
+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
134
+ insertion sort to order the MAX_THRESH items within each partition.
135
+ This is a big win, since insertion sort is faster for small, mostly
136
+ sorted array segments.
137
+
138
+ 4. The larger of the two sub-partitions is always pushed onto the
139
+ stack first, with the algorithm then concentrating on the
140
+ smaller partition. This *guarantees* no more than log (total_elems)
141
+ stack size is needed (actually O(1) in this case)! */
142
+
143
+ /* The main code starts here... */
144
+ #define QSORT(QSORT_TYPE,QSORT_BASE,QSORT_NELT,QSORT_LT) \
145
+ { \
146
+ QSORT_TYPE *const _base = (QSORT_BASE); \
147
+ const unsigned _elems = (QSORT_NELT); \
148
+ QSORT_TYPE _hold; \
149
+ \
150
+ /* Don't declare two variables of type QSORT_TYPE in a single \
151
+ * statement: eg `TYPE a, b;', in case if TYPE is a pointer, \
152
+ * expands to `type* a, b;' wich isn't what we want. \
153
+ */ \
154
+ \
155
+ if (_elems > _QSORT_MAX_THRESH) { \
156
+ QSORT_TYPE *_lo = _base; \
157
+ QSORT_TYPE *_hi = _lo + _elems - 1; \
158
+ struct { \
159
+ QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
160
+ } _stack[_QSORT_STACK_SIZE], *_top = _stack + 1; \
161
+ \
162
+ while (_QSORT_STACK_NOT_EMPTY) { \
163
+ QSORT_TYPE *_left_ptr; QSORT_TYPE *_right_ptr; \
164
+ \
165
+ /* Select median value from among LO, MID, and HI. Rearrange \
166
+ LO and HI so the three values are sorted. This lowers the \
167
+ probability of picking a pathological pivot value and \
168
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR in \
169
+ the while loops. */ \
170
+ \
171
+ QSORT_TYPE *_mid = _lo + ((_hi - _lo) >> 1); \
172
+ \
173
+ if (QSORT_LT (_mid, _lo)) \
174
+ _QSORT_SWAP (_mid, _lo, _hold); \
175
+ if (QSORT_LT (_hi, _mid)) \
176
+ _QSORT_SWAP (_mid, _hi, _hold); \
177
+ else \
178
+ goto _jump_over; \
179
+ if (QSORT_LT (_mid, _lo)) \
180
+ _QSORT_SWAP (_mid, _lo, _hold); \
181
+ _jump_over:; \
182
+ \
183
+ _left_ptr = _lo + 1; \
184
+ _right_ptr = _hi - 1; \
185
+ \
186
+ /* Here's the famous ``collapse the walls'' section of quicksort. \
187
+ Gotta like those tight inner loops! They are the main reason \
188
+ that this algorithm runs much faster than others. */ \
189
+ do { \
190
+ while (QSORT_LT (_left_ptr, _mid)) \
191
+ ++_left_ptr; \
192
+ \
193
+ while (QSORT_LT (_mid, _right_ptr)) \
194
+ --_right_ptr; \
195
+ \
196
+ if (_left_ptr < _right_ptr) { \
197
+ _QSORT_SWAP (_left_ptr, _right_ptr, _hold); \
198
+ if (_mid == _left_ptr) \
199
+ _mid = _right_ptr; \
200
+ else if (_mid == _right_ptr) \
201
+ _mid = _left_ptr; \
202
+ ++_left_ptr; \
203
+ --_right_ptr; \
204
+ } \
205
+ else if (_left_ptr == _right_ptr) { \
206
+ ++_left_ptr; \
207
+ --_right_ptr; \
208
+ break; \
209
+ } \
210
+ } while (_left_ptr <= _right_ptr); \
211
+ \
212
+ /* Set up pointers for next iteration. First determine whether \
213
+ left and right partitions are below the threshold size. If so, \
214
+ ignore one or both. Otherwise, push the larger partition's \
215
+ bounds on the stack and continue sorting the smaller one. */ \
216
+ \
217
+ if (_right_ptr - _lo <= _QSORT_MAX_THRESH) { \
218
+ if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
219
+ /* Ignore both small partitions. */ \
220
+ _QSORT_POP (_lo, _hi, _top); \
221
+ else \
222
+ /* Ignore small left partition. */ \
223
+ _lo = _left_ptr; \
224
+ } \
225
+ else if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
226
+ /* Ignore small right partition. */ \
227
+ _hi = _right_ptr; \
228
+ else if (_right_ptr - _lo > _hi - _left_ptr) { \
229
+ /* Push larger left partition indices. */ \
230
+ _QSORT_PUSH (_top, _lo, _right_ptr); \
231
+ _lo = _left_ptr; \
232
+ } \
233
+ else { \
234
+ /* Push larger right partition indices. */ \
235
+ _QSORT_PUSH (_top, _left_ptr, _hi); \
236
+ _hi = _right_ptr; \
237
+ } \
238
+ } \
239
+ } \
240
+ \
241
+ /* Once the BASE array is partially sorted by quicksort the rest \
242
+ is completely sorted using insertion sort, since this is efficient \
243
+ for partitions below MAX_THRESH size. BASE points to the \
244
+ beginning of the array to sort, and END_PTR points at the very \
245
+ last element in the array (*not* one beyond it!). */ \
246
+ \
247
+ { \
248
+ QSORT_TYPE *const _end_ptr = _base + _elems - 1; \
249
+ QSORT_TYPE *_tmp_ptr = _base; \
250
+ register QSORT_TYPE *_run_ptr; \
251
+ QSORT_TYPE *_thresh; \
252
+ \
253
+ _thresh = _base + _QSORT_MAX_THRESH; \
254
+ if (_thresh > _end_ptr) \
255
+ _thresh = _end_ptr; \
256
+ \
257
+ /* Find smallest element in first threshold and place it at the \
258
+ array's beginning. This is the smallest array element, \
259
+ and the operation speeds up insertion sort's inner loop. */ \
260
+ \
261
+ for (_run_ptr = _tmp_ptr + 1; _run_ptr <= _thresh; ++_run_ptr) \
262
+ if (QSORT_LT (_run_ptr, _tmp_ptr)) \
263
+ _tmp_ptr = _run_ptr; \
264
+ \
265
+ if (_tmp_ptr != _base) \
266
+ _QSORT_SWAP (_tmp_ptr, _base, _hold); \
267
+ \
268
+ /* Insertion sort, running from left-hand-side \
269
+ * up to right-hand-side. */ \
270
+ \
271
+ _run_ptr = _base + 1; \
272
+ while (++_run_ptr <= _end_ptr) { \
273
+ _tmp_ptr = _run_ptr - 1; \
274
+ while (QSORT_LT (_run_ptr, _tmp_ptr)) \
275
+ --_tmp_ptr; \
276
+ \
277
+ ++_tmp_ptr; \
278
+ if (_tmp_ptr != _run_ptr) { \
279
+ QSORT_TYPE *_trav = _run_ptr + 1; \
280
+ while (--_trav >= _run_ptr) { \
281
+ QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
282
+ _hold = *_trav; \
283
+ \
284
+ for (_hi = _lo = _trav; --_lo >= _tmp_ptr; _hi = _lo) \
285
+ *_hi = *_lo; \
286
+ *_hi = _hold; \
287
+ } \
288
+ } \
289
+ } \
290
+ } \
291
+ \
292
+ }
@@ -0,0 +1,29 @@
1
+ require 'ffi'
2
+ require 'fileutils'
3
+
4
+ SHARED_LIBRARY_FOLDER = File.join(File.dirname(__FILE__), '../../ffi')
5
+ SHARED_LIBRARY_NAME = File.join(SHARED_LIBRARY_FOLDER, 'libcidrmerge.so')
6
+
7
+ unless File.exist?(SHARED_LIBRARY_NAME)
8
+ FileUtils.cd(SHARED_LIBRARY_FOLDER)
9
+ %x{make}
10
+ fail "compile shared library fail, try to compile it by manual" if $?.exitstatus < 0
11
+ end
12
+
13
+ module Cidrmergerb
14
+ class Ext
15
+ extend FFI::Library
16
+ ffi_lib SHARED_LIBRARY_NAME
17
+
18
+ class Entry < FFI::ManagedStruct
19
+ layout :network => :uint,
20
+ :prefix => :uchar
21
+
22
+ def self.release(ptr)
23
+ Cidrmergerb::Ext.free_object(ptr)
24
+ end
25
+ end
26
+
27
+ attach_function :optimize, [ :pointer, :uint, :int ], :uint
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Cidrmergerb
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,61 @@
1
+ require "cidrmergerb/version"
2
+ require 'cidrmergerb/ext'
3
+ require 'ipaddr'
4
+ require 'ffi'
5
+
6
+ module Cidrmergerb
7
+
8
+ class << self
9
+ def optimize(cidrs)
10
+ pointer = build_pointer_to_cidrs(cidrs)
11
+ optimize_length = Cidrmergerb::Ext.optimize(pointer, cidrs.length, 1)
12
+
13
+ structs = wrap_with_struct(pointer, Cidrmergerb::Ext::Entry, optimize_length)
14
+ structs.map { |struct| strcut_to_cidr(struct) }
15
+ end
16
+
17
+ private
18
+ def build_pointer_to_cidrs(cidrs)
19
+ cidrs.select! {|cidr| cidr_valid?(cidr) }
20
+
21
+ pointer = alloc_memory(Cidrmergerb::Ext::Entry, cidrs.length)
22
+ entries = wrap_with_struct(pointer, Cidrmergerb::Ext::Entry, cidrs.length)
23
+
24
+ cidrs.each_with_index do |cidr, index|
25
+ ip, netmask = cidr.split('/')
26
+ entries[index][:network] = IPAddr.new(ip).to_i
27
+ entries[index][:prefix] = netmask.to_i
28
+ end
29
+
30
+ pointer
31
+ end
32
+
33
+ def cidr_valid?(cidr)
34
+ ip, netmask = cidr.split('/')
35
+ ipaddr = IPAddr.new(ip)
36
+ ipaddr && netmask.to_i.between?(1, 32)
37
+ rescue IPAddr::InvalidAddressError => e
38
+ false
39
+ end
40
+
41
+ def remove_invalid(cidrs)
42
+ cidrs.map do |cidr|
43
+ ip, netmask = cidr.split('/')
44
+ end
45
+ end
46
+
47
+ def alloc_memory(type, size)
48
+ FFI::MemoryPointer.new type, size, false
49
+ end
50
+
51
+ def wrap_with_struct(pointer, struct_type, length)
52
+ length.times.collect do |i|
53
+ struct_type.new(pointer + i * struct_type.size)
54
+ end
55
+ end
56
+
57
+ def strcut_to_cidr(struct)
58
+ "#{IPAddr.new(struct[:network], Socket::AF_INET).to_s}/#{struct[:prefix]}"
59
+ end
60
+ end
61
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cidrmergerb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Newell Zhu
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-06-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.9.10
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.9'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.9.10
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.11'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.11'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '10.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '10.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: minitest
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '5.0'
75
+ description: CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.
76
+ email:
77
+ - newell.zhu@kingaxis.com
78
+ executables: []
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - ".gitignore"
83
+ - ".travis.yml"
84
+ - Gemfile
85
+ - README.md
86
+ - Rakefile
87
+ - bin/console
88
+ - bin/setup
89
+ - cidrmergerb.gemspec
90
+ - ffi/Makefile
91
+ - ffi/cidrmerge.h
92
+ - ffi/libcidrmerge.c
93
+ - ffi/optimized-sort.h
94
+ - lib/cidrmergerb.rb
95
+ - lib/cidrmergerb/ext.rb
96
+ - lib/cidrmergerb/version.rb
97
+ homepage: https://github.com/kingaxis/cidrmergerb
98
+ licenses: []
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.5.1
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.
120
+ test_files: []