geoipdb 0.5.8 → 1.0.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.
File without changes
File without changes
@@ -0,0 +1,66 @@
1
+ import java.io.FileNotFoundException;
2
+ import java.net.InetAddress;
3
+ import java.net.UnknownHostException;
4
+ import java.util.ArrayList;
5
+ import java.util.Collections;
6
+ import java.util.HashMap;
7
+
8
+ public class IPDB
9
+ {
10
+ HashMap<Integer, City> cities;
11
+ ArrayList<IpRange> ranges;
12
+
13
+ public IPDB(String citiesFileName, String rangesFileName)
14
+ throws FileNotFoundException
15
+ {
16
+ cities = new HashMap<Integer, City>();
17
+ ranges = new ArrayList<IpRange>();
18
+ readCitiesCSV(citiesFileName);
19
+ readRangesCSV(rangesFileName);
20
+ }
21
+
22
+ public IpRange findRangeForIp(byte[] ip)
23
+ {
24
+ IpRange search = new IpRange(ip);
25
+ int index = Collections.binarySearch(ranges, search);
26
+ if (index < 0)
27
+ return null;
28
+ return ranges.get(index);
29
+ }
30
+
31
+ public City findCityForIpRange(IpRange range)
32
+ {
33
+ return cities.get(range.cityCode);
34
+ }
35
+
36
+ public ArrayList<IpRange> get_ranges()
37
+ {
38
+ return ranges;
39
+ }
40
+
41
+ private void readCitiesCSV(String file_name)
42
+ throws FileNotFoundException
43
+ {
44
+ CsvReader reader = new CsvReader(file_name);
45
+ String[] line = null;
46
+ City city = null;
47
+ reader.readLine(); // skip first line
48
+ while ((line = reader.readLine()) != null) {
49
+ city = new City(line);
50
+ cities.put(city.cityCode, city);
51
+ }
52
+ }
53
+
54
+ private void readRangesCSV(String file_name)
55
+ throws FileNotFoundException
56
+ {
57
+ CsvReader reader = new CsvReader(file_name);
58
+ String[] line = null;
59
+ reader.readLine(); // skip first line
60
+ while ((line = reader.readLine()) != null) {
61
+ if (line.length < 5)
62
+ continue;
63
+ ranges.add(new IpRange(line));
64
+ }
65
+ }
66
+ }
@@ -1,3 +1,6 @@
1
+ import java.net.InetAddress;
2
+ import java.net.UnknownHostException;
3
+
1
4
  public class IpRange implements Comparable<IpRange>
2
5
  {
3
6
  long from;
@@ -16,12 +19,18 @@ public class IpRange implements Comparable<IpRange>
16
19
  this.ispName = rangeValues[4].length() > 100 ? rangeValues[4].substring(0, 100) : rangeValues[4];
17
20
  }
18
21
 
19
- public IpRange(String from, String to)
22
+ public IpRange(byte[] from, byte[] to)
20
23
  {
21
24
  this.from = ipToLong(from);
22
25
  this.to = ipToLong(to);
23
26
  }
24
27
 
28
+ public IpRange(byte[] from)
29
+ {
30
+ this.from = ipToLong(from);
31
+ this.to = 0;
32
+ }
33
+
25
34
  public int getCityCode()
26
35
  {
27
36
  return cityCode;
@@ -59,14 +68,19 @@ public class IpRange implements Comparable<IpRange>
59
68
 
60
69
  private long ipToLong(String ip)
61
70
  {
62
- long result = 0;
63
-
64
- if (!(ip == null || ip.equals(""))) {
65
- for (String octet : ip.split("\\.")) {
66
- result = (result << 8) | Integer.parseInt(octet);
67
- }
71
+ try {
72
+ return ipToLong(InetAddress.getByName(ip).getAddress());
73
+ } catch (UnknownHostException e) {
74
+ return 0;
68
75
  }
76
+ }
69
77
 
78
+ private long ipToLong(byte[] ip)
79
+ {
80
+ long result = 0;
81
+ for (byte octet : ip) {
82
+ result = (result << 8) | (octet & 0xFF);
83
+ }
70
84
  return result;
71
85
  }
72
86
 
metadata CHANGED
@@ -1,89 +1,81 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geoipdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.8
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LiquidM, Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-30 00:00:00.000000000 Z
11
+ date: 2014-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake-compiler
15
- requirement: !ruby/object:Gem::Requirement
14
+ name: liquid-ext
15
+ version_requirements: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
20
+ requirement: !ruby/object:Gem::Requirement
23
21
  requirements:
24
- - - ">="
22
+ - - '>='
25
23
  - !ruby/object:Gem::Version
26
24
  version: '0'
27
- description: Fast GeoIpDb implementation for Ruby
25
+ prerelease: false
26
+ type: :runtime
27
+ description: Fast IPDB implementation for JRuby
28
28
  email:
29
29
  - opensource@liquidm.com
30
30
  executables: []
31
- extensions:
32
- - ext/geoipdb/extconf.rb
31
+ extensions: []
33
32
  extra_rdoc_files: []
34
33
  files:
35
- - ".gitignore"
36
- - ".rspec"
37
- - ".travis.yml"
34
+ - .gitignore
35
+ - .rspec
36
+ - .ruby-version
37
+ - .travis.yml
38
38
  - Gemfile
39
39
  - LICENSE.txt
40
+ - Makefile
40
41
  - README.md
41
42
  - Rakefile
42
- - ext/geoipdb/extconf.rb
43
- - ext/geoipdb/geoipdb.c
44
- - ext/geoipdb/ipdb.c
45
- - ext/geoipdb/ipdb.h
46
- - ext/geoipdb/src/City.java
47
- - ext/geoipdb/src/CsvReader.java
48
- - ext/geoipdb/src/GeoIpDb.java
49
- - ext/geoipdb/src/IpRange.java
50
43
  - geoipdb.gemspec
51
- - lib/cgeoipdb.rb
44
+ - lib/geoipdb.jar
52
45
  - lib/geoipdb.rb
53
- - lib/ip_information.rb
54
- - lib/jgeoipdb.rb
55
46
  - sample_data/cities.csv
56
- - sample_data/citiess_corrupt.csv
57
47
  - sample_data/ip_ranges.csv
58
- - sample_data/ip_ranges_corrupt.csv
59
48
  - spec/geoipdb_spec.rb
60
49
  - spec/spec_helper.rb
50
+ - src/City.java
51
+ - src/CsvReader.java
52
+ - src/IPDB.java
53
+ - src/IpRange.java
61
54
  homepage: http://github.com/liquidm/geoipdb
62
55
  licenses:
63
56
  - MIT
64
57
  metadata: {}
65
- post_install_message:
58
+ post_install_message:
66
59
  rdoc_options: []
67
60
  require_paths:
68
61
  - lib
69
- - ext
70
62
  required_ruby_version: !ruby/object:Gem::Requirement
71
63
  requirements:
72
- - - ">="
64
+ - - '>='
73
65
  - !ruby/object:Gem::Version
74
66
  version: '0'
75
67
  required_rubygems_version: !ruby/object:Gem::Requirement
76
68
  requirements:
77
- - - ">="
69
+ - - '>='
78
70
  - !ruby/object:Gem::Version
79
71
  version: '0'
80
72
  requirements: []
81
- rubyforge_project:
82
- rubygems_version: 2.2.0
83
- signing_key:
73
+ rubyforge_project:
74
+ rubygems_version: 2.2.2
75
+ signing_key:
84
76
  specification_version: 4
85
- summary: Fast GeoIpDb implementation for Ruby
77
+ summary: Fast IPDB implementation for JRuby
86
78
  test_files:
87
79
  - spec/geoipdb_spec.rb
88
80
  - spec/spec_helper.rb
89
- has_rdoc:
81
+ has_rdoc:
@@ -1,3 +0,0 @@
1
- require "mkmf"
2
-
3
- create_makefile("geoipdb/geoipdb")
@@ -1,107 +0,0 @@
1
- #include "ruby.h"
2
- #include "ipdb.h"
3
-
4
- /**
5
- Ruby Wrapper
6
- */
7
-
8
- typedef struct geipdb {
9
- IPDB *db;
10
- } geoipdb;
11
-
12
- static VALUE cIpDb;
13
-
14
- // free the memory used by the db, called by the Ruby-GC
15
- void geoipdb_free(geoipdb *gi) {
16
- if(gi == NULL)
17
- return;
18
- if (gi->db != NULL){
19
- if(gi->db->cities != NULL ){
20
- free(gi->db->cities);
21
- gi->db->cities = NULL;
22
- }
23
- if(gi->db->ranges != NULL ){
24
- free(gi->db->ranges);
25
- gi->db->ranges = NULL;
26
- }
27
- if(gi->db != NULL){
28
- free(gi->db);
29
- }
30
- }
31
- }
32
-
33
-
34
- VALUE ipdb_init(VALUE self, VALUE cities_file_name, VALUE ranges_file_name, VALUE cache_file_name) {
35
- geoipdb *gi;
36
-
37
- Check_Type(cities_file_name, T_STRING);
38
- Check_Type(ranges_file_name, T_STRING);
39
- Check_Type(cache_file_name, T_STRING);
40
-
41
- char *cities_csv_file = RSTRING_PTR(cities_file_name);
42
- char *ranges_csv_file = RSTRING_PTR(ranges_file_name);
43
- char *cache_file = RSTRING_PTR(cache_file_name);
44
-
45
- gi = ALLOC(geoipdb);
46
-
47
- gi->db= init_db(cities_csv_file, ranges_csv_file, cache_file);
48
-
49
- if(gi->db == NULL)
50
- {
51
- if(DEBUG)
52
- printf("Could not init DB!\n");
53
- /*
54
- TODO: Add geoipdb_free in this case.. though not important for production...
55
- */
56
- return Qnil;
57
- }else{
58
- if(DEBUG)
59
- printf("\nDB Init completed!\n");
60
- return(Data_Wrap_Struct(cIpDb, 0, geoipdb_free, gi));
61
- }
62
- }
63
-
64
-
65
- VALUE build_ip_information_object(IpRange *range, City *city, char* isp) {
66
- VALUE CIpInformation;
67
-
68
- CIpInformation = rb_const_get(rb_cObject, rb_intern("IpInformation"));
69
-
70
- VALUE ip_information = rb_funcall(CIpInformation, rb_intern("new"), 0);
71
- rb_ivar_set(ip_information, rb_intern("@country_iso_code"), rb_str_new2(city->country_iso2) );
72
- rb_ivar_set(ip_information, rb_intern("@city_name"), rb_str_new2(city->name) );
73
- rb_ivar_set(ip_information, rb_intern("@city_code"), INT2FIX(city->city_code) );
74
- rb_ivar_set(ip_information, rb_intern("@lng"), rb_float_new(city->lng) );
75
- rb_ivar_set(ip_information, rb_intern("@lat"), rb_float_new(city->lat) );
76
- rb_ivar_set(ip_information, rb_intern("@is_mobile"), range->is_mobile == 1 ? Qtrue : Qfalse );
77
- rb_ivar_set(ip_information, rb_intern("@isp_name"), isp == NULL ? Qnil : ID2SYM( rb_intern(isp) ) );
78
-
79
- return ip_information;
80
- }
81
-
82
- VALUE ipdb_information_for_ip(VALUE self, VALUE ip_string){
83
- char *ip = RSTRING_PTR(ip_string);
84
- geoipdb *gi;
85
-
86
- Data_Get_Struct(self, geoipdb, gi);
87
-
88
- IpRange* ip_range = find_range_for_ip(gi->db, ip);
89
-
90
- if(!ip_range)
91
- return Qnil;
92
-
93
- City * city = find_city_for_ip_range(gi->db, ip_range);
94
- if(!city)
95
- return Qnil;
96
-
97
- char* isp = find_isp_for_ip_range(gi->db, ip_range);
98
-
99
- return build_ip_information_object(ip_range, city, isp);
100
- }
101
-
102
- void Init_geoipdb(void)
103
- {
104
- cIpDb = rb_define_class( "GeoIpDb", rb_cObject);
105
- rb_define_singleton_method( cIpDb, "init", ipdb_init, 3);
106
- rb_define_method( cIpDb, "information_for_ip", ipdb_information_for_ip, 1);
107
- }
@@ -1,668 +0,0 @@
1
- #include "ipdb.h"
2
-
3
- #include <search.h>
4
- #include <stdio.h>
5
- #include <string.h>
6
- #include <stdlib.h>
7
- #include <sys/time.h>
8
-
9
- const char country_iso2_codes[251][3] = { "--","ad","ae","af","ag","ai","al","am","an",
10
- "ao","aq","ar","as","at","au","aw","az","ba","bb",
11
- "bd","be","bf","bg","bh","bi","bj","bm","bn","bo",
12
- "br","bs","bt","bv","bw","by","bz","ca","cc","cd",
13
- "cf","cg","ch","ci","ck","cl","cm","cn","co","cr",
14
- "cu","cv","cx","cy","cz","de","dj","dk","dm","do",
15
- "dz","ec","ee","eg","eh","er","es","et","fi","fj",
16
- "fk","fm","fo","fr","ga","gb","gd","ge","gf",
17
- "gh","gi","gl","gm","gn","gp","gq","gr","gs","gt",
18
- "gu","gw","gy","hk","hm","hn","hr","ht","hu","id",
19
- "ie","il","in","io","iq","ir","is","it","jm","jo",
20
- "jp","ke","kg","kh","ki","km","kn","kp","kr","kw",
21
- "ky","kz","la","lb","lc","li","lk","lr","ls","lt",
22
- "lu","lv","ly","ma","mc","md","mg","mh","mk","ml",
23
- "mm","mn","mo","mp","mq","mr","ms","mt","mu","mv",
24
- "mw","mx","my","mz","na","nc","ne","nf","ng","ni",
25
- "nl","no","np","nr","nu","nz","om","pa","pe","pf",
26
- "pg","ph","pk","pl","pm","pn","pr","ps","pt","pw",
27
- "py","qa","re","ro","ru","rw","sa","sb","sc","sd",
28
- "se","sg","sh","si","sj","sk","sl","sm","sn","so",
29
- "sr","st","sv","sy","sz","tc","td","tf","tg","th",
30
- "tj","tk","tm","tn","to","tl","tr","tt","tv","tw",
31
- "tz","ua","ug","um","us","uy","uz","va","vc","ve",
32
- "vg","vi","vn","vu","wf","ws","ye","yt","rs","za",
33
- "zm","me","zw","ax","gg","im","je",
34
- "bl","mf","bq","cw","ss","sx"};
35
-
36
- static const unsigned num_countries = (unsigned)(sizeof(country_iso2_codes)/sizeof(country_iso2_codes[0]));
37
-
38
- const char country_iso3_codes[251][4] = { "--","and","are","afg","atg","aia","alb","arm","ant",
39
- "ago","ata","arg","asm","aut","aus","abw","aze","bih","brb",
40
- "bgd","bel","bfa","bgr","bhr","bdi","ben","bmu","brn","bol",
41
- "bra","bhs","btn","bvt","bwa","blr","blz","can","cck","cod",
42
- "caf","cog","che","civ","cok","chl","cmr","chn","col","cri",
43
- "cub","cpv","cxr","cyp","cze","deu","dji","dnk","dma","dom",
44
- "dza","ecu","est","egy","esh","eri","esp","eth","fin","fji",
45
- "flk","fsm","fro","fra","gab","gbr","grd","geo","guf",
46
- "gha","gib","grl","gmb","gin","glp","gnq","grc","sgs","gtm",
47
- "gum","gnb","guy","hkg","hmd","hnd","hrv","hti","hun","idn",
48
- "irl","isr","ind","iot","irq","irn","isl","ita","jam","jor",
49
- "jpn","ken","kgz","khm","kir","com","kna","prk","kor","kwt",
50
- "cym","kaz","lao","lbn","lca","lie","lka","lbr","lso","ltu",
51
- "lux","lva","lby","mar","mco","mda","mdg","mhl","mkd","mli",
52
- "mmr","mng","mac","mnp","mtq","mrt","msr","mlt","mus","mdv",
53
- "mwi","mex","mys","moz","nam","ncl","ner","nfk","nga","nic",
54
- "nld","nor","npl","nru","niu","nzl","omn","pan","per","pyf",
55
- "png","phl","pak","pol","spm","pcn","pri","pse","prt","plw",
56
- "pry","qat","reu","rou","rus","rwa","sau","slb","syc","sdn",
57
- "swe","sgp","shn","svn","sjm","svk","sle","smr","sen","som",
58
- "sur","stp","slv","syr","swz","tca","tcd","atf","tgo","tha",
59
- "tjk","tkl","tkm","tun","ton","tls","tur","tto","tuv","twn",
60
- "tza","ukr","uga","umi","usa","ury","uzb","vat","vct","ven",
61
- "vgb","vir","vnm","vut","wlf","wsm","yem","myt","srb","zaf",
62
- "zmb","mne","zwe","ala","ggy","imn","jey",
63
- "blm","maf","bes","cuw","ssd","sxm"};
64
-
65
-
66
- void
67
- print_range(const IpRange* e){
68
- printf( "from: %lu, to:%lu ->City-idx: %i \n",e->from, e->to,e->city_index );
69
- }
70
-
71
- void
72
- print_ranges(IPDB * db){
73
- int i;
74
- for(i = 0; i < db->ranges_count; ++i)
75
- {
76
- print_range(&(db->ranges[i]));
77
- }
78
- }
79
-
80
- void
81
- print_city(const City * e){
82
- if(e == NULL)
83
- {
84
- return;
85
- }
86
- printf( "City: code:%i, name:%s, country: %s, lat: %10.7f, lng: %10.7f \n",e->city_code, e->name, e->country_iso3, e->lat, e->lng );
87
- }
88
-
89
- void
90
- print_cities(IPDB * db){
91
- int i;
92
- for(i = 0; i < db->cities_count; ++i)
93
- {
94
- print_city(&(db->cities[i]));
95
- }
96
- }
97
-
98
- void print_stats(IPDB * db){
99
- printf("DB STATS: \n");
100
- printf("\tCities: %i\n", db->cities_count);
101
- printf("\tRanges: %i\n", db->ranges_count);
102
- }
103
-
104
- double
105
- get_time(struct timeval *tim){
106
- gettimeofday(tim, NULL);
107
- return tim->tv_sec+(tim->tv_usec/1000000.0);
108
- }
109
-
110
-
111
- unsigned long
112
- ip_to_int(const char *addr){
113
- unsigned int c, octet, t;
114
- unsigned long ipnum;
115
- int i = 3;
116
-
117
- octet = ipnum = 0;
118
- while ((c = *addr++)) {
119
- if (c == '.') {
120
- if (octet > 255)
121
- return 0;
122
- ipnum <<= 8;
123
- ipnum += octet;
124
- i--;
125
- octet = 0;
126
- } else {
127
- t = octet;
128
- octet <<= 3;
129
- octet += t;
130
- octet += t;
131
- c -= '0';
132
- if (c > 9)
133
- return 0;
134
- octet += c;
135
- }
136
- }
137
- if ((octet > 255) || (i != 0))
138
- return 0;
139
- ipnum <<= 8;
140
- return ipnum + octet;
141
- }
142
-
143
-
144
- unsigned char con_type_to_int(char* con_type) {
145
- // possible values
146
- // ?
147
- // dialup
148
- // broadband
149
- // cable
150
- // xdsl
151
- // mobile
152
- // t1
153
- // t3
154
- // oc3
155
- // oc12
156
- // satellite
157
- // wireless
158
- if(strlen(con_type) > 0 && (con_type[0] == 'm'))
159
- return 1;
160
- return 0;
161
- }
162
-
163
- // Function to compare
164
- // - either two ip-ranges: i.e.: a(from...to) <=> b(from...to)
165
- // - or a ip(i.e. range without to) and an ip-range: i.e. a(from...NULL) <=> b(from...to); a(from...to) <=> b(from ... NULL)
166
- int compare_ranges(const void *fa, const void *fb) {
167
- if(fa == NULL)
168
- {
169
- if(DEBUG){printf("FA IS NULL!!!\n");}
170
- return 0;
171
- }
172
- if(fb == NULL)
173
- {
174
- if(DEBUG){printf("FB IS NULL!!!\n");}
175
- return 0;
176
- }
177
-
178
-
179
- const IpRange *a = (IpRange *) fa;
180
- const IpRange *b = (IpRange *) fb;
181
-
182
- if(a->from>0 && a->to>0 && b->from>0 && b->to>0){ //regular case: both entries are ranges
183
- if(a->to < b->from) {
184
- return -1;
185
- }else if(a->from > b->to){
186
- return +1;
187
- }else{
188
- return 0;
189
- }
190
- }else if(a->to == 0 && b->to>0){//a is a search_object
191
- if(a->from < b->from) {
192
- return -1;
193
- }else if(a->from > b->to){
194
- return +1;
195
- }else{
196
- return 0;
197
- }
198
- }else if(b->to == 0 && a->to>0){//b is a search_object
199
- if(b->from < a->from){
200
- return -1;
201
- }else if(b->from > a->to){
202
- return +1;
203
- }else{
204
- return 0;
205
- }
206
- }else if(a->to == 0 && b->to == 0){ //both are search objects - this should not happen!
207
- return a->from - b->from;
208
- }
209
- return 0;
210
- }
211
-
212
-
213
- int
214
- compare_cities(const void *a, const void *b){
215
- const City city_a = *(City*)a;
216
- const City city_b = * (City*) b;
217
- // sort cities by city_code
218
- return city_a.city_code - city_b.city_code;
219
- }
220
-
221
- void
222
- sort_cities(IPDB * db){
223
- if(DEBUG)
224
- printf("Sorting %i Cities in db...\n", db->cities_count);
225
-
226
- struct timeval tim;
227
- double t1 = get_time(&tim);
228
-
229
- qsort(db->cities,db->cities_count,sizeof(City), compare_cities);
230
- if(DEBUG)
231
- printf("\n Sorting cities needed %.6lf seconds\n", get_time(&tim)-t1);
232
- }
233
-
234
-
235
- int // returns a city-index
236
- city_index_by_code(IPDB * db, int city_code){
237
- City *search, *result;
238
- search = malloc(sizeof(City));
239
- search->city_code = city_code;
240
- result = (City*) bsearch(search, db->cities, db->cities_count, sizeof(City), compare_cities);
241
-
242
- if(search != NULL)
243
- free(search);
244
-
245
- if(result == NULL)
246
- {
247
- if(DEBUG)
248
- printf("Could not find searched city with code: %i \n", city_code);
249
- return -1;
250
- }else{
251
- int index;
252
- index = (result - db->cities);
253
- return index;
254
- }
255
- }
256
-
257
-
258
- IpRange* find_range_for_ip(IPDB *db, char *ip) {
259
- IpRange* search;
260
- IpRange* result;
261
- search = (IpRange *)malloc(sizeof(IpRange));
262
-
263
- if(db == NULL)
264
- {
265
- if(DEBUG){printf("ERROR: DB ist NULL! \n");}
266
- return NULL;
267
- }
268
-
269
- if(db->ranges_count == 0)
270
- {
271
- if(DEBUG){printf("ERROR: DB has no Ranges Data. Can not search!\n");}
272
- return NULL;
273
- }
274
-
275
- search->from = ip_to_int(ip);
276
- search->to=0;
277
- search->city_index = 0;
278
- if(DEBUG)
279
- printf("Searching for: ip=%s, ipnum=%lu \n", ip, search->from);
280
- result = (IpRange*)bsearch(search, db->ranges, db->ranges_count, sizeof(IpRange), compare_ranges);
281
- if(search != NULL)
282
- free(search);
283
-
284
- if(result == NULL)
285
- {
286
- if(DEBUG)
287
- printf("ERROR: Could not find the IP: %s! THIS SHOULD NOT HAPPEN!\n", ip);
288
- return NULL;
289
- } else {
290
- if(DEBUG) {
291
- printf("Found Range: \t");
292
- print_range(result);
293
- }
294
- return (IpRange*)result;
295
- }
296
- }
297
-
298
- City * find_city_for_ip_range(IPDB * db, IpRange* range)
299
- {
300
- if(!db || !range)
301
- return NULL;
302
-
303
- if(db->cities_count == 0)
304
- {
305
- if(DEBUG)
306
- printf("ERROR: DB has no City Data. Can not search!\n");
307
- return NULL;
308
- }
309
-
310
- if( range->city_index <= 0 || range->city_index >= db->cities_count )
311
- {
312
- if(DEBUG)
313
- printf("ERROR: Could not find city with index: %i - THIS SHOULD NOT HAPPEN!\n", range->city_index);
314
- }
315
-
316
- return &(db->cities[range->city_index]);
317
- }
318
-
319
- char* find_isp_for_ip_range(IPDB * db, IpRange* range)
320
- {
321
- if( range == NULL || range->isp_index < 0){
322
- if(DEBUG){printf("Could not find isp for isp_index=%i\n", range->isp_index);}
323
- return NULL;
324
- }
325
- return db->isps[range->isp_index];
326
- }
327
-
328
- int16
329
- isp_index_by_name(IPDB * db, char* isp_name){
330
- if(isp_name == NULL || isp_name == "")
331
- return -1;
332
- if( db->isps_count > 0){
333
- int16 i = 0;
334
- for( i = 0; i < db->isps_count; i++)
335
- {
336
- if( strcmp(db->isps[i], isp_name)==0)
337
- {
338
- return i;
339
- }
340
- }
341
- }
342
- // add new isp
343
- if(db->isps_count < MAX_ISPS_COUNT){
344
- int16 new_index = db->isps_count;
345
- strncpy(db->isps[new_index], isp_name, MAX_ISP_NAME_LENGTH);
346
- db->isps_count++;
347
- return new_index;
348
- }else{
349
- if(DEBUG){printf("ERROR: MAX_ISPS_COUNT = %i limit reached - this should not happen!\n", MAX_ISPS_COUNT);}
350
- return -1;
351
- }
352
- }
353
-
354
-
355
-
356
- // read ip-ranges from csv file, of format:
357
- // from_ip|to_ip|contype|city_code
358
- void
359
- read_ranges_csv(IPDB * db){
360
- struct timeval tim;
361
- double t1 = get_time(&tim);
362
-
363
- db->ranges = malloc(sizeof(IpRange) * db->max_ranges_count);
364
-
365
- if(DEBUG)
366
- printf("Parsing RANGES-CSV-file: %s\n", db->ranges_csv_file);
367
- FILE * f = fopen(db->ranges_csv_file, "rt");
368
- if(f == NULL)
369
- {
370
- if(DEBUG)
371
- printf("Could not open the CSV-file: %s\n", db->ranges_csv_file);
372
- return;
373
- }
374
- char line[256];
375
- char* from;
376
- char* to;
377
- char* city_code;
378
- int city_index;
379
-
380
- char* con_type;
381
- char* isp_name;
382
- uint16 isp_index;
383
-
384
- int invalid_cities_count = 0;
385
-
386
- IpRange* entry;
387
- db->ranges_count = 0;
388
- while (fgets(line, sizeof(line) ,f) && db->ranges_count < db->max_ranges_count){
389
- from = NULL;
390
- to = NULL;
391
- city_code = NULL;
392
- city_index = 0;
393
-
394
- con_type = NULL;
395
- isp_name = NULL;
396
- int16 isp_index = -1;
397
-
398
- if(DEBUG && db->ranges_count % 1000000 == 0)
399
- printf("Worked lines: %i\n", db->ranges_count);
400
-
401
- from = strtok(line, RANGES_DELIM);
402
- to = strtok(NULL, RANGES_DELIM);
403
- con_type = strtok(NULL, RANGES_DELIM);
404
- city_code = strtok(NULL, RANGES_DELIM);
405
- isp_name = strtok(NULL, RANGES_DELIM);
406
-
407
- city_index = city_index_by_code(db, atoi(city_code));
408
- isp_index = isp_index_by_name(db, isp_name);
409
-
410
- if(city_index < 0)
411
- {
412
- if(DEBUG)
413
- printf("Could not find city for code: %i\n", atoi(city_code));
414
- invalid_cities_count ++;
415
- continue;
416
- }else{
417
- entry = &(db->ranges[db->ranges_count]);
418
- entry->from = ip_to_int(from);
419
- entry->to = ip_to_int(to);
420
- entry->is_mobile = con_type_to_int(con_type);
421
- entry->city_index = city_index;
422
- entry->isp_index = isp_index;
423
-
424
- db->ranges_count++;
425
- }
426
- }
427
- if(DEBUG)
428
- {
429
- if(invalid_cities_count ){printf("Found invalid cities: %i\n", invalid_cities_count);}
430
- printf("\n Parsing of %i records needed %.6lf seconds\n", db->ranges_count, get_time(&tim)-t1);
431
- }
432
- }
433
-
434
-
435
-
436
- //translate country iso3 to iso2
437
- char *
438
- iso2_code(char* iso3){
439
- int i = 0;
440
- for( i = 0; i < num_countries; i++)
441
- {
442
- if( strcmp(country_iso3_codes[i],iso3)==0)
443
- {
444
- return (char*) country_iso2_codes[i];
445
- }
446
- }
447
- return (char*) country_iso2_codes[0];
448
- }
449
-
450
- //read city-data from csv-file of format:
451
- // COUNTRY,REGION,CITY-NAME,METRO-CODE,CITY-CODE,LATITUDE,LONGITUDE
452
- void
453
- read_cities_csv(IPDB * db){
454
- struct timeval tim;
455
- double t1 = get_time(&tim);
456
-
457
- db->cities_count = 0;
458
- db->cities = malloc(sizeof(City) * db->max_cities_count);
459
-
460
- if(DEBUG)
461
- printf("Parsing Cities-CSV-file: %s\n", db->cities_csv_file);
462
- FILE * f = fopen(db->cities_csv_file, "rt");
463
- if(f == NULL)
464
- {
465
- if(DEBUG)
466
- printf("Could not open the Cities-CSV-file: %s\n", db->cities_csv_file);
467
- return;
468
- }
469
- char line[256];
470
- char *country, *region, *name,*metro_code,*city_code,*lat,*lng ;
471
- int i = 0;
472
- City* entry;
473
-
474
- while (fgets(line,sizeof(line),f) && db->cities_count < db->max_cities_count){
475
- i++;
476
- if(i == 1)
477
- continue;//skip the header
478
-
479
- if(DEBUG && i % 1000000 == 0)
480
- {
481
- printf("Worked lines: %i\n", i);
482
- }
483
- // COUNTRY,REGION,CITY-NAME,METRO-CODE,CITY-CODE,LATITUDE,LONGITUDE
484
- country = strtok(line, CITIES_DELIM);
485
- region = strtok(NULL, CITIES_DELIM);
486
- name = strtok(NULL, CITIES_DELIM);
487
- metro_code = strtok(NULL, CITIES_DELIM);
488
- city_code = strtok(NULL, CITIES_DELIM);
489
- lat = strtok(NULL, CITIES_DELIM);
490
- lng = strtok(NULL, CITIES_DELIM);
491
-
492
- entry = &(db->cities[db->cities_count]);
493
-
494
- strncpy(entry->country_iso3, country, strlen(country));
495
-
496
- strncpy(entry->country_iso2, iso2_code(country), 2);
497
- strncpy(entry->name, name, strlen(name));
498
-
499
- entry->city_code = atoi(city_code);
500
- entry->lat = atof(lat);
501
- entry->lng = atof(lng);
502
- db->cities_count++;
503
- }
504
- if(DEBUG)
505
- printf("\n Parsing of %i records needed %.6lf seconds\n", db->cities_count, get_time(&tim)-t1);
506
- }
507
-
508
- /**
509
- cache-file is an exact binary copy of the ranges+cities-arrays from memory,
510
- the layout goes like this:
511
- db->cities_count [4 Bytes]
512
- db->ranges_count [4 Bytes]
513
-
514
- db->cities [sizeof(City)=24 x db->ranges_count Bytes]
515
- db->ranges [sizeof(IpRange)=24 x db->ranges_count Bytes]
516
- */
517
- void
518
- write_cache_file(IPDB * db){
519
- struct timeval tim;
520
- double t1 = get_time(&tim);
521
- int objects_written;
522
-
523
- FILE * f;
524
- f = fopen(db->cache_file_name, "w");
525
- if(f==NULL){
526
- if(DEBUG)
527
- printf("Could not open Cache-File: %s\n", db->cache_file_name);
528
- return;
529
- }
530
- if(DEBUG){
531
- printf("Dumping %i records to cache-file: %s\n\n", db->ranges_count, db->cache_file_name);
532
-
533
- //write the record length at file header
534
- printf("Writing DB-Header of length: %li\n",sizeof(db->ranges_count));
535
-
536
- printf("RecordLength: %li\n",sizeof(IpRange));
537
- printf("FieldLength: %li\n",sizeof(db->ranges[0].from));
538
- }
539
- //write the header: i.e.: numbers of records
540
- fwrite(&(db->cities_count), sizeof(db->cities_count),1,f);
541
- fwrite(&(db->isps_count), sizeof(db->isps_count),1,f);
542
- fwrite(&(db->ranges_count), sizeof(db->ranges_count),1,f);
543
-
544
- if(DEBUG)
545
- printf("Writing Contents with %i cities, a %li bytes each, should = %li \n", db->cities_count, sizeof(City), db->cities_count * sizeof(City));
546
- //write the actual data: all the ranges-array-buffer:
547
- objects_written = fwrite(db->cities, sizeof(City), db->cities_count, f);
548
-
549
- if(DEBUG)
550
- printf("Writing Contents with %i isps, a %i bytes each, should = %i \n", db->isps_count, MAX_ISP_NAME_LENGTH, db->isps_count * MAX_ISP_NAME_LENGTH);
551
- //write the actual data: all the ranges-array-buffer:
552
- objects_written += fwrite(db->isps, MAX_ISP_NAME_LENGTH, db->isps_count, f);
553
-
554
- if(DEBUG)
555
- printf("Writing Contents with %i ranges, a %li bytes each, should = %li \n", db->ranges_count, sizeof(IpRange), db->ranges_count * sizeof(IpRange));
556
- //write the actual data: all the ranges-array-buffer:
557
- objects_written += fwrite(db->ranges, sizeof(IpRange), db->ranges_count, f);
558
-
559
-
560
- fclose(f);
561
- if(DEBUG)
562
- printf("\n Writing CacheFile of %i objects needed %.6lf seconds\n", objects_written, get_time(&tim)-t1);
563
- }
564
-
565
- int
566
- read_cache_file(IPDB * db){
567
- struct timeval tim;
568
- double t1 = get_time(&tim);
569
- FILE * f;
570
- f = fopen(db->cache_file_name, "r");
571
- if(f==NULL){
572
- if(DEBUG)
573
- printf("Could not open Cache-File: %s\n", db->cache_file_name);
574
- return 0;
575
- }
576
- int cities_header_read = fread(&(db->cities_count), sizeof(db->cities_count),1,f);
577
- int isps_header_read = fread(&(db->isps_count), sizeof(db->isps_count),1,f);
578
- int ranges_header_read = fread(&(db->ranges_count), sizeof(db->ranges_count),1,f);
579
-
580
-
581
- if(cities_header_read == 0 || isps_header_read == 0 || ranges_header_read == 0 || db->cities_count == 0 || db->isps_count ==0 || db->ranges_count ==0)
582
- {
583
- if(DEBUG){printf("Could not read Cities-Header from Cache-File: %s\n", db->cache_file_name);}
584
- return 0;
585
- }
586
- if(DEBUG)
587
- printf("Reading DB-Header from Cache-File: %s, with %i cities, %iisps and %i ranges\n",db->cache_file_name, db->cities_count, db->isps_count, db->ranges_count);
588
-
589
- int objects_read = 0;
590
- if(DEBUG)
591
- printf("Allocating: %lu for cities-array \n", sizeof(City)*(db->cities_count));
592
- db->cities = malloc(sizeof(City) * db->cities_count);
593
- objects_read += fread(db->cities, sizeof(City),db->cities_count,f);
594
-
595
- if(DEBUG)
596
- printf("Reading in the isps into preallocated buffer of size: %lu\n", sizeof(db->isps));
597
- objects_read += fread(db->isps, MAX_ISP_NAME_LENGTH, db->isps_count,f);
598
-
599
- if(DEBUG)
600
- printf("Allocating: %lu for ranges-array \n", sizeof(IpRange)*(db->ranges_count));
601
- db->ranges = malloc(sizeof(IpRange) * db->ranges_count);
602
- objects_read += fread(db->ranges, sizeof(IpRange),db->ranges_count,f);
603
-
604
-
605
- fclose(f);
606
- if(DEBUG)
607
- printf("Reading cacheFile of %i objects needed %.6lf seconds\n", objects_read, get_time(&tim)-t1);
608
- return objects_read;
609
- }
610
-
611
- void
612
- benchmark_search(IPDB * db,int count){
613
- printf("(Naiv) benchmark of the City-Search-Function with %i counts \n", count);
614
- struct timeval tim;
615
- double t1 = get_time(&tim);
616
- int i;
617
- City * city;
618
-
619
- for(i=0;i<count; i++){
620
- IpRange* range = find_range_for_ip(db,"278.50.47.0");
621
- City* city = find_city_for_ip_range(db,range);
622
- }
623
- double delta = get_time(&tim)-t1;
624
-
625
- printf("\n\nSearch: %.6lf seconds elapsed, i.e. %.6lf Ops/Second \n", delta, count / delta);
626
- }
627
-
628
- IPDB * init_db(char * cities_csv_file, char * ranges_csv_file, char * cache_file_name){
629
- if(DEBUG)
630
- printf("Initializing db\n");
631
- IPDB *db;
632
- db = (IPDB*)malloc(sizeof(IPDB));
633
- if (db == NULL) //no memory left
634
- return NULL;
635
- db->cities = NULL;
636
- db->ranges = NULL;
637
- db->cache_file_name = cache_file_name;
638
-
639
- db->cities_csv_file = cities_csv_file;
640
- db->max_cities_count = MAX_CITIES_COUNT;
641
- db->ranges_csv_file = ranges_csv_file;
642
- db->max_ranges_count = MAX_RANGES_COUNT;
643
-
644
- db->isps_count = 0;
645
-
646
- if(USE_CACHE && read_cache_file(db) > 0){
647
- if(DEBUG)
648
- printf("Loaded DB from Cache-File with %i records \n", db->ranges_count);
649
- }else{
650
- if(DEBUG)
651
- printf("Initializing IPDB from CSV-file: %s \n", db->ranges_csv_file);
652
- read_cities_csv(db);
653
- if(db->cities_count == 0)
654
- {
655
- return NULL;
656
- }
657
- sort_cities(db);
658
- read_ranges_csv(db);
659
- if(db!=NULL && db->ranges_count > 0 && USE_CACHE)
660
- {
661
- if(DEBUG)
662
- printf("Got %i records from CSV-file, writing to cache...\n", db->ranges_count);
663
- write_cache_file(db);
664
- }
665
- }
666
- return db;
667
- }
668
-