cidrmergerb 0.1.0

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