geoipdb 0.1.4 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +1 -1
- data/README.markdown +7 -7
- data/Rakefile +6 -5
- data/VERSION +1 -1
- data/ext/geoipdb/Makefile +187 -0
- data/ext/{build.sh → geoipdb/build.sh} +0 -0
- data/ext/geoipdb/extconf.rb +5 -0
- data/ext/geoipdb/geoipdb.c +112 -0
- data/ext/{ipdb.c → geoipdb/ipdb.c} +134 -45
- data/ext/{ipdb.h → geoipdb/ipdb.h} +29 -9
- data/geoipdb.gemspec +20 -16
- data/lib/geoipdb.rb +17 -0
- data/sample_data/ip_ranges.csv +11 -11
- data/sample_data/ip_ranges_corrupt.csv +11 -11
- data/spec/geoipdb_spec.rb +34 -14
- data/spec/spec_helper.rb +2 -1
- data/test.rb +9 -0
- metadata +29 -26
- data/ext/extconf.rb +0 -5
- data/ext/geoipdb.c +0 -109
- data/ext/test.c +0 -42
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.
|
4
4
|
|
5
|
-
* Returns a GeoLocation
|
5
|
+
* Returns a GeoLocation and additional information for a given IP.
|
6
6
|
* Reads Data from CSV-Files and uses internal binary caching.
|
7
7
|
|
8
8
|
## Usage
|
9
9
|
|
10
|
-
db =
|
11
|
-
|
12
|
-
|
10
|
+
db = IpDb.init "city_codes.csv", "ip_city.txt", "ip_city.cache"
|
11
|
+
ip_info = db.information_for_ip("178.0.0.1")
|
12
|
+
ip_info.inspect
|
13
|
+
=> #<IpInformation:0x101385c78 @city_name="eschborn", @city_code="ax5", @lng=8.55, @country_iso_code="de", @lat=50.133333, @is_mobile=true>
|
13
14
|
|
14
15
|
== Copyright
|
15
16
|
|
16
|
-
Copyright (c) 2010
|
17
|
-
further details.
|
18
|
-
|
17
|
+
Copyright (c) 2010 madvertise GmbH. See LICENSE.txt for
|
18
|
+
further details.
|
data/Rakefile
CHANGED
@@ -13,14 +13,15 @@ require 'jeweler'
|
|
13
13
|
Jeweler::Tasks.new do |gem|
|
14
14
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
15
|
gem.name = "geoipdb"
|
16
|
-
gem.homepage = "http://github.com/
|
16
|
+
gem.homepage = "http://github.com/madvertise/geoipdb"
|
17
17
|
gem.license = "MIT"
|
18
18
|
gem.summary = %Q{Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.}
|
19
|
-
gem.description = %Q{Returns a GeoLocation
|
19
|
+
gem.description = %Q{Returns a GeoLocation and additional information for given IP. Reads Data from CSV-Files and uses internal binary caching.}
|
20
20
|
gem.email = "eugeniusmartinus@googlemail.com"
|
21
|
-
gem.authors = ["Eugen Martin"]
|
22
|
-
gem.extensions = ['ext/extconf.rb']
|
23
|
-
gem.
|
21
|
+
gem.authors = ["Eugen Martin", "Martin Karlsch"]
|
22
|
+
gem.extensions = ['ext/geoipdb/extconf.rb']
|
23
|
+
gem.require_paths = ["lib","ext"]
|
24
|
+
|
24
25
|
end
|
25
26
|
Jeweler::RubygemsDotOrgTasks.new
|
26
27
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1
|
1
|
+
0.3.1
|
@@ -0,0 +1,187 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /Users/eugen/.rvm/rubies/ruby-1.9.2-p180/include/ruby-1.9.1
|
8
|
+
hdrdir = /Users/eugen/.rvm/rubies/ruby-1.9.2-p180/include/ruby-1.9.1
|
9
|
+
arch_hdrdir = /Users/eugen/.rvm/rubies/ruby-1.9.2-p180/include/ruby-1.9.1/$(arch)
|
10
|
+
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
11
|
+
prefix = $(DESTDIR)/Users/eugen/.rvm/rubies/ruby-1.9.2-p180
|
12
|
+
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
13
|
+
exec_prefix = $(prefix)
|
14
|
+
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
15
|
+
sitehdrdir = $(rubyhdrdir)/site_ruby
|
16
|
+
rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
|
17
|
+
vendordir = $(rubylibprefix)/vendor_ruby
|
18
|
+
sitedir = $(rubylibprefix)/site_ruby
|
19
|
+
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
20
|
+
mandir = $(datarootdir)/man
|
21
|
+
localedir = $(datarootdir)/locale
|
22
|
+
libdir = $(exec_prefix)/lib
|
23
|
+
psdir = $(docdir)
|
24
|
+
pdfdir = $(docdir)
|
25
|
+
dvidir = $(docdir)
|
26
|
+
htmldir = $(docdir)
|
27
|
+
infodir = $(datarootdir)/info
|
28
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
29
|
+
oldincludedir = $(DESTDIR)/usr/include
|
30
|
+
includedir = $(prefix)/include
|
31
|
+
localstatedir = $(prefix)/var
|
32
|
+
sharedstatedir = $(prefix)/com
|
33
|
+
sysconfdir = $(prefix)/etc
|
34
|
+
datadir = $(datarootdir)
|
35
|
+
datarootdir = $(prefix)/share
|
36
|
+
libexecdir = $(exec_prefix)/libexec
|
37
|
+
sbindir = $(exec_prefix)/sbin
|
38
|
+
bindir = $(exec_prefix)/bin
|
39
|
+
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
40
|
+
archdir = $(rubylibdir)/$(arch)
|
41
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
42
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
43
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
44
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
45
|
+
|
46
|
+
CC = gcc
|
47
|
+
CXX = g++
|
48
|
+
LIBRUBY = $(LIBRUBY_SO)
|
49
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
50
|
+
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
51
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
52
|
+
OUTFLAG = -o
|
53
|
+
COUTFLAG = -o
|
54
|
+
|
55
|
+
RUBY_EXTCONF_H =
|
56
|
+
cflags = $(optflags) $(debugflags) $(warnflags)
|
57
|
+
optflags = -O3
|
58
|
+
debugflags = -ggdb
|
59
|
+
warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long
|
60
|
+
CFLAGS = -fno-common $(cflags) -fno-common -pipe
|
61
|
+
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
62
|
+
DEFS =
|
63
|
+
CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
|
64
|
+
CXXFLAGS = $(CFLAGS) $(cxxflags)
|
65
|
+
ldflags = -L. -L/usr/local/lib
|
66
|
+
dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace
|
67
|
+
ARCH_FLAG =
|
68
|
+
DLDFLAGS = $(ldflags) $(dldflags)
|
69
|
+
LDSHARED = $(CC) -dynamic -bundle
|
70
|
+
LDSHAREDXX = $(CXX) -dynamic -bundle
|
71
|
+
AR = ar
|
72
|
+
EXEEXT =
|
73
|
+
|
74
|
+
RUBY_BASE_NAME = ruby
|
75
|
+
RUBY_INSTALL_NAME = ruby
|
76
|
+
RUBY_SO_NAME = ruby.1.9.1
|
77
|
+
arch = x86_64-darwin10.7.0
|
78
|
+
sitearch = $(arch)
|
79
|
+
ruby_version = 1.9.1
|
80
|
+
ruby = /Users/eugen/.rvm/rubies/ruby-1.9.2-p180/bin/ruby
|
81
|
+
RUBY = $(ruby)
|
82
|
+
RM = rm -f
|
83
|
+
RM_RF = $(RUBY) -run -e rm -- -rf
|
84
|
+
RMDIRS = $(RUBY) -run -e rmdir -- -p
|
85
|
+
MAKEDIRS = mkdir -p
|
86
|
+
INSTALL = /usr/bin/install -c
|
87
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
88
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
89
|
+
COPY = cp
|
90
|
+
|
91
|
+
#### End of system configuration section. ####
|
92
|
+
|
93
|
+
preload =
|
94
|
+
|
95
|
+
libpath = . $(libdir)
|
96
|
+
LIBPATH = -L. -L$(libdir)
|
97
|
+
DEFFILE =
|
98
|
+
|
99
|
+
CLEANFILES = mkmf.log
|
100
|
+
DISTCLEANFILES =
|
101
|
+
DISTCLEANDIRS =
|
102
|
+
|
103
|
+
extout =
|
104
|
+
extout_prefix =
|
105
|
+
target_prefix = /geoipdb
|
106
|
+
LOCAL_LIBS =
|
107
|
+
LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
|
108
|
+
SRCS = geoipdb.c ipdb.c
|
109
|
+
OBJS = geoipdb.o ipdb.o
|
110
|
+
TARGET = geoipdb
|
111
|
+
DLLIB = $(TARGET).bundle
|
112
|
+
EXTSTATIC =
|
113
|
+
STATIC_LIB =
|
114
|
+
|
115
|
+
BINDIR = $(bindir)
|
116
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
117
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
118
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
119
|
+
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
120
|
+
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
121
|
+
|
122
|
+
TARGET_SO = $(DLLIB)
|
123
|
+
CLEANLIBS = $(TARGET).bundle
|
124
|
+
CLEANOBJS = *.o *.bak
|
125
|
+
|
126
|
+
all: $(DLLIB)
|
127
|
+
static: $(STATIC_LIB)
|
128
|
+
.PHONY: all install static install-so install-rb
|
129
|
+
.PHONY: clean clean-so clean-rb
|
130
|
+
|
131
|
+
clean-rb-default::
|
132
|
+
clean-rb::
|
133
|
+
clean-so::
|
134
|
+
clean: clean-so clean-rb-default clean-rb
|
135
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
136
|
+
|
137
|
+
distclean-rb-default::
|
138
|
+
distclean-rb::
|
139
|
+
distclean-so::
|
140
|
+
distclean: clean distclean-so distclean-rb-default distclean-rb
|
141
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
142
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
143
|
+
@-$(RMDIRS) $(DISTCLEANDIRS)
|
144
|
+
|
145
|
+
realclean: distclean
|
146
|
+
install: install-so install-rb
|
147
|
+
|
148
|
+
install-so: $(RUBYARCHDIR)
|
149
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
150
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
151
|
+
@-$(MAKEDIRS) $(@D)
|
152
|
+
$(INSTALL_PROG) $(DLLIB) $(@D)
|
153
|
+
install-rb: pre-install-rb install-rb-default
|
154
|
+
install-rb-default: pre-install-rb-default
|
155
|
+
pre-install-rb: Makefile
|
156
|
+
pre-install-rb-default: Makefile
|
157
|
+
$(RUBYARCHDIR):
|
158
|
+
$(MAKEDIRS) $@
|
159
|
+
|
160
|
+
site-install: site-install-so site-install-rb
|
161
|
+
site-install-so: install-so
|
162
|
+
site-install-rb: install-rb
|
163
|
+
|
164
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
165
|
+
|
166
|
+
.cc.o:
|
167
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
168
|
+
|
169
|
+
.cxx.o:
|
170
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
171
|
+
|
172
|
+
.cpp.o:
|
173
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
174
|
+
|
175
|
+
.C.o:
|
176
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
177
|
+
|
178
|
+
.c.o:
|
179
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
180
|
+
|
181
|
+
$(DLLIB): $(OBJS) Makefile
|
182
|
+
@-$(RM) $(@)
|
183
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
|
File without changes
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#include "ipdb.h"
|
2
|
+
|
3
|
+
#include "ruby.h"
|
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
|
+
printf("Freeing memory for the GeoIpDb.. \n");
|
17
|
+
if(gi == NULL)
|
18
|
+
return;
|
19
|
+
if (gi->db != NULL){
|
20
|
+
if(gi->db->cities != NULL ){
|
21
|
+
printf("..freeing cities \n");
|
22
|
+
free(gi->db->cities);
|
23
|
+
gi->db->cities = NULL;
|
24
|
+
}
|
25
|
+
if(gi->db->ranges != NULL ){
|
26
|
+
printf("..freeing ranges \n");
|
27
|
+
free(gi->db->ranges);
|
28
|
+
gi->db->ranges = NULL;
|
29
|
+
}
|
30
|
+
if(gi->db != NULL){
|
31
|
+
printf("..freeing ipdb \n");
|
32
|
+
free(gi->db);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
VALUE ipdb_init(VALUE self, VALUE cities_file_name, VALUE ranges_file_name, VALUE cache_file_name) {
|
39
|
+
geoipdb *gi;
|
40
|
+
|
41
|
+
Check_Type(cities_file_name, T_STRING);
|
42
|
+
Check_Type(ranges_file_name, T_STRING);
|
43
|
+
Check_Type(cache_file_name, T_STRING);
|
44
|
+
|
45
|
+
char *cities_csv_file = RSTRING_PTR(cities_file_name);
|
46
|
+
char *ranges_csv_file = RSTRING_PTR(ranges_file_name);
|
47
|
+
char *cache_file = RSTRING_PTR(cache_file_name);
|
48
|
+
|
49
|
+
gi = ALLOC(geoipdb);
|
50
|
+
|
51
|
+
gi->db= init_db(cities_csv_file, ranges_csv_file, cache_file);
|
52
|
+
|
53
|
+
|
54
|
+
if(gi->db == NULL)
|
55
|
+
{
|
56
|
+
if(DEBUG)
|
57
|
+
printf("Could not init DB!\n");
|
58
|
+
/*
|
59
|
+
TODO: Add geoipdb_free in this case.. though not important for production...
|
60
|
+
*/
|
61
|
+
return Qnil;
|
62
|
+
}else{
|
63
|
+
if(DEBUG)
|
64
|
+
printf("\nDB Init completed!\n");
|
65
|
+
return(Data_Wrap_Struct(cIpDb, 0, geoipdb_free, gi));
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
VALUE build_ip_information_object(IpRange *range, City *city, char* isp) {
|
71
|
+
VALUE CIpInformation;
|
72
|
+
|
73
|
+
CIpInformation = rb_const_get(rb_cObject, rb_intern("IpInformation"));
|
74
|
+
|
75
|
+
VALUE ip_information = rb_funcall(CIpInformation, rb_intern("new"), 0);
|
76
|
+
rb_ivar_set(ip_information, rb_intern("@country_iso_code"), rb_str_new2(city->country_iso2) );
|
77
|
+
rb_ivar_set(ip_information, rb_intern("@city_name"), rb_str_new2(city->name) );
|
78
|
+
rb_ivar_set(ip_information, rb_intern("@city_code"), INT2FIX(city->city_code) );
|
79
|
+
rb_ivar_set(ip_information, rb_intern("@lng"), rb_float_new(city->lng) );
|
80
|
+
rb_ivar_set(ip_information, rb_intern("@lat"), rb_float_new(city->lat) );
|
81
|
+
rb_ivar_set(ip_information, rb_intern("@is_mobile"), range->is_mobile == 1 ? Qtrue : Qfalse );
|
82
|
+
rb_ivar_set(ip_information, rb_intern("@isp_name"), isp == NULL ? Qnil : ID2SYM( rb_intern(isp) ) );
|
83
|
+
|
84
|
+
return ip_information;
|
85
|
+
}
|
86
|
+
|
87
|
+
VALUE ipdb_information_for_ip(VALUE self, VALUE ip_string){
|
88
|
+
char *ip = RSTRING_PTR(ip_string);
|
89
|
+
geoipdb *gi;
|
90
|
+
|
91
|
+
Data_Get_Struct(self, geoipdb, gi);
|
92
|
+
|
93
|
+
IpRange* ip_range = find_range_for_ip(gi->db, ip);
|
94
|
+
|
95
|
+
if(!ip_range)
|
96
|
+
return Qnil;
|
97
|
+
|
98
|
+
City * city = find_city_for_ip_range(gi->db, ip_range);
|
99
|
+
if(!city)
|
100
|
+
return Qnil;
|
101
|
+
|
102
|
+
char* isp = find_isp_for_ip_range(gi->db, ip_range);
|
103
|
+
|
104
|
+
return build_ip_information_object(ip_range, city, isp);
|
105
|
+
}
|
106
|
+
|
107
|
+
void Init_geoipdb(void)
|
108
|
+
{
|
109
|
+
cIpDb = rb_define_class( "GeoIpDb", rb_cObject);
|
110
|
+
rb_define_singleton_method( cIpDb, "init", ipdb_init, 3);
|
111
|
+
rb_define_method( cIpDb, "information_for_ip", ipdb_information_for_ip, 1);
|
112
|
+
}
|
@@ -6,9 +6,6 @@
|
|
6
6
|
#include <stdlib.h>
|
7
7
|
#include <sys/time.h>
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
9
|
const char country_iso2_codes[253][3] = { "--","ap","eu","ad","ae","af","ag","ai","al","am","an",
|
13
10
|
"ao","aq","ar","as","at","au","aw","az","ba","bb",
|
14
11
|
"bd","be","bf","bg","bh","bi","bj","bm","bn","bo",
|
@@ -144,7 +141,26 @@ ip_to_int(const char *addr){
|
|
144
141
|
ipnum <<= 8;
|
145
142
|
return ipnum + octet;
|
146
143
|
}
|
147
|
-
|
144
|
+
|
145
|
+
|
146
|
+
unsigned char con_type_to_int(char* con_type) {
|
147
|
+
// possible values
|
148
|
+
// ?
|
149
|
+
// dialup
|
150
|
+
// broadband
|
151
|
+
// cable
|
152
|
+
// xdsl
|
153
|
+
// mobile
|
154
|
+
// t1
|
155
|
+
// t3
|
156
|
+
// oc3
|
157
|
+
// oc12
|
158
|
+
// satellite
|
159
|
+
// wireless
|
160
|
+
if(strlen(con_type) > 0 && (con_type[0] == 'm'))
|
161
|
+
return 1;
|
162
|
+
return 0;
|
163
|
+
}
|
148
164
|
|
149
165
|
// Function to compare
|
150
166
|
// - either two ip-ranges: i.e.: a(from...to) <=> b(from...to)
|
@@ -250,13 +266,10 @@ city_index_by_code(IPDB * db, uint16 city_code){
|
|
250
266
|
}
|
251
267
|
|
252
268
|
|
253
|
-
|
254
|
-
|
255
|
-
IpRange
|
269
|
+
IpRange* find_range_for_ip(IPDB *db, char *ip) {
|
270
|
+
IpRange* search;
|
271
|
+
IpRange* result;
|
256
272
|
search = (IpRange *)malloc(sizeof(IpRange));
|
257
|
-
void * res;
|
258
|
-
|
259
|
-
// print_stats(db);
|
260
273
|
|
261
274
|
if(db == NULL)
|
262
275
|
{
|
@@ -275,24 +288,29 @@ city_by_ip(IPDB *db, char *ip){
|
|
275
288
|
search->city_index = 0;
|
276
289
|
if(DEBUG)
|
277
290
|
printf("Searching for: ip=%s, ipnum=%lu \n", ip, search->from);
|
278
|
-
|
279
|
-
res = bsearch(search, db->ranges, db->ranges_count, sizeof(IpRange), compare_ranges);
|
291
|
+
result = (IpRange*)bsearch(search, db->ranges, db->ranges_count, sizeof(IpRange), compare_ranges);
|
280
292
|
if(search != NULL)
|
281
293
|
free(search);
|
282
294
|
|
283
|
-
if(
|
295
|
+
if(result == NULL)
|
284
296
|
{
|
285
297
|
if(DEBUG)
|
286
|
-
|
298
|
+
printf("ERROR: Could not find the IP: %s! THIS SHOULD NOT HAPPEN!\n", ip);
|
287
299
|
return NULL;
|
288
|
-
}else{
|
289
|
-
|
290
|
-
if(DEBUG){
|
300
|
+
} else {
|
301
|
+
if(DEBUG) {
|
291
302
|
printf("Found Range: \t");
|
292
303
|
print_range(result);
|
293
|
-
}
|
304
|
+
}
|
305
|
+
return (IpRange*)result;
|
294
306
|
}
|
295
|
-
|
307
|
+
}
|
308
|
+
|
309
|
+
City * find_city_for_ip_range(IPDB * db, IpRange* range)
|
310
|
+
{
|
311
|
+
if(!db || !range)
|
312
|
+
return NULL;
|
313
|
+
|
296
314
|
if(db->cities_count == 0)
|
297
315
|
{
|
298
316
|
if(DEBUG)
|
@@ -300,21 +318,55 @@ city_by_ip(IPDB *db, char *ip){
|
|
300
318
|
return NULL;
|
301
319
|
}
|
302
320
|
|
303
|
-
|
304
|
-
if(result->city_index >0 && result->city_index < db->cities_count)
|
321
|
+
if( range->city_index <= 0 || range->city_index >= db->cities_count )
|
305
322
|
{
|
306
|
-
// address the city directly via the array-idx
|
307
|
-
return &(db->cities[result->city_index]);
|
308
|
-
} else {
|
309
323
|
if(DEBUG)
|
310
|
-
printf("ERROR: Could not find city with index: %i - THIS SHOULD NOT HAPPEN!\n",
|
311
|
-
|
324
|
+
printf("ERROR: Could not find city with index: %i - THIS SHOULD NOT HAPPEN!\n", range->city_index);
|
325
|
+
}
|
326
|
+
|
327
|
+
return &(db->cities[range->city_index]);
|
328
|
+
}
|
329
|
+
|
330
|
+
char* find_isp_for_ip_range(IPDB * db, IpRange* range)
|
331
|
+
{
|
332
|
+
if( range == NULL || range->isp_index < 0 || range->isp_index > MAX_ISPS_COUNT){
|
333
|
+
printf("Could not find isp for isp_index=%i", range->isp_index);
|
334
|
+
return NULL;
|
335
|
+
}
|
336
|
+
return db->isps[range->isp_index];
|
337
|
+
}
|
338
|
+
|
339
|
+
int16
|
340
|
+
isp_index_by_name(IPDB * db, char* isp_name){
|
341
|
+
if(isp_name == NULL || isp_name == "")
|
342
|
+
return -1;
|
343
|
+
if( db->isps_count > 0){
|
344
|
+
int16 i = 0;
|
345
|
+
for( i = 0; i < db->isps_count; i++)
|
346
|
+
{
|
347
|
+
if( strcmp(db->isps[i], isp_name)==0)
|
348
|
+
{
|
349
|
+
return i;
|
350
|
+
}
|
351
|
+
}
|
352
|
+
}
|
353
|
+
// TODO: malloc more space if needed
|
354
|
+
// add new isp
|
355
|
+
if(db->isps_count < MAX_ISPS_COUNT){
|
356
|
+
int16 new_index = db->isps_count;
|
357
|
+
strncpy(db->isps[new_index], isp_name, MAX_ISP_NAME_LENGTH);
|
358
|
+
db->isps_count++;
|
359
|
+
return new_index;
|
360
|
+
}else{
|
361
|
+
printf("ERROR: MAX_ISPS_COUNT = %i limit reached - this should not happen!", MAX_ISPS_COUNT);
|
362
|
+
return -1;
|
312
363
|
}
|
313
364
|
}
|
314
365
|
|
315
366
|
|
367
|
+
|
316
368
|
// read ip-ranges from csv file, of format:
|
317
|
-
// from_ip|to_ip|city_code
|
369
|
+
// from_ip|to_ip|contype|city_code
|
318
370
|
void
|
319
371
|
read_ranges_csv(IPDB * db){
|
320
372
|
struct timeval tim;
|
@@ -332,39 +384,56 @@ read_ranges_csv(IPDB * db){
|
|
332
384
|
return;
|
333
385
|
}
|
334
386
|
char line[256];
|
335
|
-
char* from
|
336
|
-
char* to
|
337
|
-
char* city_code
|
338
|
-
int invalid_cities_count = 0;
|
387
|
+
char* from;
|
388
|
+
char* to;
|
389
|
+
char* city_code;
|
339
390
|
int city_index;
|
391
|
+
|
392
|
+
char* con_type;
|
393
|
+
char* isp_name;
|
394
|
+
uint16 isp_index;
|
395
|
+
|
396
|
+
int invalid_cities_count = 0;
|
340
397
|
|
341
398
|
IpRange* entry;
|
342
399
|
db->ranges_count = 0;
|
343
|
-
while (fgets(line,sizeof(line),f) && db->ranges_count < db->max_ranges_count){
|
400
|
+
while (fgets(line, sizeof(line) ,f) && db->ranges_count < db->max_ranges_count){
|
401
|
+
from = NULL;
|
402
|
+
to = NULL;
|
403
|
+
city_code = NULL;
|
404
|
+
city_index = 0;
|
405
|
+
|
406
|
+
con_type = NULL;
|
407
|
+
isp_name = NULL;
|
408
|
+
int16 isp_index = -1;
|
409
|
+
|
344
410
|
if(DEBUG && db->ranges_count % 1000000 == 0)
|
345
411
|
printf("Worked lines: %i\n", db->ranges_count);
|
346
412
|
|
347
413
|
from = strtok(line, RANGES_DELIM);
|
348
414
|
to = strtok(NULL, RANGES_DELIM);
|
415
|
+
con_type = strtok(NULL, RANGES_DELIM);
|
349
416
|
city_code = strtok(NULL, RANGES_DELIM);
|
417
|
+
isp_name = strtok(NULL, RANGES_DELIM);
|
418
|
+
|
350
419
|
city_index = city_index_by_code(db, atoi(city_code));
|
420
|
+
isp_index = isp_index_by_name(db, isp_name);
|
421
|
+
|
351
422
|
if(city_index < 0)
|
352
|
-
{
|
423
|
+
{
|
353
424
|
if(DEBUG)
|
354
425
|
printf("Could not find city for code: %i", atoi(city_code));
|
355
426
|
invalid_cities_count ++;
|
356
427
|
continue;
|
357
428
|
}else{
|
358
429
|
entry = &(db->ranges[db->ranges_count]);
|
359
|
-
|
360
430
|
entry->from = ip_to_int(from);
|
361
|
-
entry->to = ip_to_int(to);
|
362
|
-
|
363
|
-
|
431
|
+
entry->to = ip_to_int(to);
|
432
|
+
entry->is_mobile = con_type_to_int(con_type);
|
364
433
|
entry->city_index = city_index;
|
365
|
-
|
366
|
-
|
367
|
-
//
|
434
|
+
entry->isp_index = isp_index;
|
435
|
+
|
436
|
+
// printf("from: %u,to: %u, city_code:%s, city_index: %i\n",entry->from,entry->to,city_code, entry->city_index);
|
368
437
|
// printf("working record nr: %li\n", db->ranges_count);
|
369
438
|
db->ranges_count++;
|
370
439
|
}
|
@@ -488,13 +557,20 @@ write_cache_file(IPDB * db){
|
|
488
557
|
printf("FieldLength: %li\n",sizeof(db->ranges[0].from));
|
489
558
|
}
|
490
559
|
//write the header: i.e.: numbers of records
|
491
|
-
fwrite(&(db->cities_count), sizeof(db->cities_count),1,f);
|
560
|
+
fwrite(&(db->cities_count), sizeof(db->cities_count),1,f);
|
561
|
+
fwrite(&(db->isps_count), sizeof(db->isps_count),1,f);
|
492
562
|
fwrite(&(db->ranges_count), sizeof(db->ranges_count),1,f);
|
493
563
|
|
494
564
|
if(DEBUG)
|
495
565
|
printf("Writing Contents with %i cities, a %li bytes each, should = %li \n", db->cities_count, sizeof(City), db->cities_count * sizeof(City));
|
496
566
|
//write the actual data: all the ranges-array-buffer:
|
497
567
|
objects_written = fwrite(db->cities, sizeof(City), db->cities_count, f);
|
568
|
+
|
569
|
+
if(DEBUG)
|
570
|
+
printf("Writing Contents with %i isps, a %li bytes each, should = %li \n", db->isps_count, MAX_ISP_NAME_LENGTH, db->isps_count * MAX_ISP_NAME_LENGTH);
|
571
|
+
//write the actual data: all the ranges-array-buffer:
|
572
|
+
objects_written += fwrite(db->isps, MAX_ISP_NAME_LENGTH, db->isps_count, f);
|
573
|
+
|
498
574
|
if(DEBUG)
|
499
575
|
printf("Writing Contents with %i ranges, a %li bytes each, should = %li \n", db->ranges_count, sizeof(IpRange), db->ranges_count * sizeof(IpRange));
|
500
576
|
//write the actual data: all the ranges-array-buffer:
|
@@ -518,22 +594,28 @@ read_cache_file(IPDB * db){
|
|
518
594
|
return 0;
|
519
595
|
}
|
520
596
|
int cities_header_read = fread(&(db->cities_count), sizeof(db->cities_count),1,f);
|
597
|
+
int isps_header_read = fread(&(db->isps_count), sizeof(db->isps_count),1,f);
|
521
598
|
int ranges_header_read = fread(&(db->ranges_count), sizeof(db->ranges_count),1,f);
|
522
599
|
|
523
600
|
|
524
|
-
if(cities_header_read == 0 || ranges_header_read == 0 || db->cities_count == 0 || db->ranges_count ==0
|
601
|
+
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)
|
525
602
|
{
|
526
603
|
printf("Could not read Cities-Header from Cache-File: %s", db->cache_file_name);
|
527
604
|
return 0;
|
528
605
|
}
|
529
606
|
if(DEBUG)
|
530
|
-
printf("Reading DB-Header from Cache-File: %s, with %i cities and %i ranges\n",db->cache_file_name, db->cities_count, db->ranges_count);
|
607
|
+
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);
|
531
608
|
|
532
609
|
int objects_read = 0;
|
533
610
|
if(DEBUG)
|
534
611
|
printf("Allocating: %lu for cities-array \n", sizeof(City)*(db->cities_count));
|
535
612
|
db->cities = malloc(sizeof(City) * db->cities_count);
|
536
613
|
objects_read += fread(db->cities, sizeof(City),db->cities_count,f);
|
614
|
+
|
615
|
+
if(DEBUG)
|
616
|
+
printf("Reading in the isps into preallocated buffer of size: ", sizeof(db->isps));
|
617
|
+
objects_read += fread(db->isps, MAX_ISP_NAME_LENGTH, db->isps_count,f);
|
618
|
+
|
537
619
|
if(DEBUG)
|
538
620
|
printf("Allocating: %lu for ranges-array \n", sizeof(IpRange)*(db->ranges_count));
|
539
621
|
db->ranges = malloc(sizeof(IpRange) * db->ranges_count);
|
@@ -554,8 +636,9 @@ benchmark_search(IPDB * db,int count){
|
|
554
636
|
int i;
|
555
637
|
City * city;
|
556
638
|
|
557
|
-
for(i=0;i<count; i++){
|
558
|
-
|
639
|
+
for(i=0;i<count; i++){
|
640
|
+
IpRange* range = find_range_for_ip(db,"278.50.47.0");
|
641
|
+
City* city = find_city_for_ip_range(db,range);
|
559
642
|
}
|
560
643
|
double delta = get_time(&tim)-t1;
|
561
644
|
|
@@ -563,6 +646,8 @@ benchmark_search(IPDB * db,int count){
|
|
563
646
|
}
|
564
647
|
|
565
648
|
IPDB * init_db(char * cities_csv_file, char * ranges_csv_file, char * cache_file_name){
|
649
|
+
if(DEBUG)
|
650
|
+
printf("Initializing db");
|
566
651
|
IPDB *db;
|
567
652
|
db = (IPDB*)malloc(sizeof(IPDB));
|
568
653
|
if (db == NULL) //no memory left
|
@@ -575,6 +660,10 @@ IPDB * init_db(char * cities_csv_file, char * ranges_csv_file, char * cache_file
|
|
575
660
|
db->max_cities_count = MAX_CITIES_COUNT;
|
576
661
|
db->ranges_csv_file = ranges_csv_file;
|
577
662
|
db->max_ranges_count = MAX_RANGES_COUNT;
|
663
|
+
|
664
|
+
// db->isps = NULL;
|
665
|
+
// db->isps = malloc(MAX_ISP_NAME_LENGTH * MAX_ISPS_COUNT);
|
666
|
+
db->isps_count = 0;
|
578
667
|
|
579
668
|
|
580
669
|
if(USE_CACHE && read_cache_file(db) > 0){
|
@@ -11,21 +11,31 @@ typedef unsigned short uint16;
|
|
11
11
|
typedef int int32;
|
12
12
|
#endif
|
13
13
|
|
14
|
+
#ifdef RSTRING_PTR
|
15
|
+
#else
|
16
|
+
# define RSTRING_LEN(x) (RSTRING(x)->len)
|
17
|
+
# define RSTRING_PTR(x) (RSTRING(x)->ptr)
|
18
|
+
#endif
|
19
|
+
|
20
|
+
|
21
|
+
#define RANGES_DELIM ",\n"
|
22
|
+
#define CITIES_DELIM ",\n"
|
14
23
|
|
15
|
-
#define RANGES_DELIM "|"
|
16
|
-
#define CITIES_DELIM ","
|
17
24
|
#define MAX_CITIES_COUNT 100000 //Usually we have about 50 000 Cities
|
18
|
-
#define MAX_RANGES_COUNT 10000000 //Usually we have about 6 Mio IP-Ranges
|
25
|
+
#define MAX_RANGES_COUNT 10000000 //Usually we have about 6 Mio IP-Ranges
|
19
26
|
|
27
|
+
#define MAX_ISPS_COUNT 100000
|
28
|
+
#define MAX_ISP_NAME_LENGTH 100
|
20
29
|
|
21
30
|
#define USE_CACHE 1
|
22
31
|
#define DEBUG 0
|
23
32
|
|
24
33
|
typedef struct{
|
25
34
|
unsigned long from;
|
26
|
-
unsigned long to;
|
27
|
-
|
35
|
+
unsigned long to;
|
36
|
+
unsigned char is_mobile;
|
28
37
|
uint16 city_index; //index of the city in the cities-array
|
38
|
+
int16 isp_index; //index of the isp in the isps-array
|
29
39
|
} IpRange;
|
30
40
|
|
31
41
|
typedef struct{
|
@@ -47,11 +57,14 @@ typedef struct{
|
|
47
57
|
unsigned int cities_count;
|
48
58
|
unsigned int max_cities_count;
|
49
59
|
|
50
|
-
|
51
60
|
char *cache_file_name; // a binary file to store the whole db.....
|
52
61
|
IpRange * ranges;
|
53
62
|
City * cities;
|
54
63
|
|
64
|
+
char isps[MAX_ISPS_COUNT][MAX_ISP_NAME_LENGTH]; // a fixed size array of strings should be enough here...do not expect the isps to grow dramatically..
|
65
|
+
uint16 isps_count;
|
66
|
+
|
67
|
+
|
55
68
|
} IPDB;
|
56
69
|
|
57
70
|
|
@@ -59,11 +72,18 @@ typedef struct{
|
|
59
72
|
IPDB *
|
60
73
|
init_db(char * cities_csv_file, char * ranges_csv_file, char * cache_file_name);
|
61
74
|
|
62
|
-
City *
|
63
|
-
city_by_ip(IPDB *db, char *ip);
|
64
75
|
|
65
76
|
void
|
66
77
|
print_city(const City * e);
|
67
78
|
|
68
79
|
void
|
69
|
-
benchmark_search(IPDB * db,int count);
|
80
|
+
benchmark_search(IPDB * db,int count);
|
81
|
+
|
82
|
+
IpRange*
|
83
|
+
find_range_for_ip(IPDB *db, char *ip);
|
84
|
+
|
85
|
+
City*
|
86
|
+
find_city_for_ip_range(IPDB * db, IpRange* range);
|
87
|
+
|
88
|
+
char*
|
89
|
+
find_isp_for_ip_range(IPDB * db, IpRange* range);
|
data/geoipdb.gemspec
CHANGED
@@ -5,14 +5,14 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{geoipdb}
|
8
|
-
s.version = "0.1
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Eugen Martin"]
|
12
|
-
s.date = %q{2011-
|
13
|
-
s.description = %q{Returns a GeoLocation
|
11
|
+
s.authors = ["Eugen Martin", "Martin Karlsch"]
|
12
|
+
s.date = %q{2011-06-14}
|
13
|
+
s.description = %q{Returns a GeoLocation and additional information for given IP. Reads Data from CSV-Files and uses internal binary caching.}
|
14
14
|
s.email = %q{eugeniusmartinus@googlemail.com}
|
15
|
-
s.extensions = ["ext/extconf.rb"]
|
15
|
+
s.extensions = ["ext/geoipdb/extconf.rb"]
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"LICENSE.txt",
|
18
18
|
"README.markdown"
|
@@ -25,21 +25,26 @@ Gem::Specification.new do |s|
|
|
25
25
|
"README.markdown",
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
|
-
"ext/
|
29
|
-
"ext/
|
30
|
-
"ext/geoipdb.
|
31
|
-
"ext/
|
32
|
-
"ext/ipdb.
|
33
|
-
"ext/
|
28
|
+
"ext/geoipdb/Makefile",
|
29
|
+
"ext/geoipdb/build.sh",
|
30
|
+
"ext/geoipdb/extconf.rb",
|
31
|
+
"ext/geoipdb/geoipdb.c",
|
32
|
+
"ext/geoipdb/ipdb.c",
|
33
|
+
"ext/geoipdb/ipdb.h",
|
34
34
|
"geoipdb.gemspec",
|
35
35
|
"lib/geoipdb.rb",
|
36
|
+
"sample_data/cities.csv",
|
37
|
+
"sample_data/citiess_corrupt.csv",
|
38
|
+
"sample_data/ip_ranges.csv",
|
39
|
+
"sample_data/ip_ranges_corrupt.csv",
|
36
40
|
"spec/geoipdb_spec.rb",
|
37
|
-
"spec/spec_helper.rb"
|
41
|
+
"spec/spec_helper.rb",
|
42
|
+
"test.rb"
|
38
43
|
]
|
39
|
-
s.homepage = %q{http://github.com/
|
44
|
+
s.homepage = %q{http://github.com/madvertise/geoipdb}
|
40
45
|
s.licenses = ["MIT"]
|
41
|
-
s.require_paths = ["ext"]
|
42
|
-
s.rubygems_version = %q{1.3
|
46
|
+
s.require_paths = ["lib", "ext"]
|
47
|
+
s.rubygems_version = %q{1.5.3}
|
43
48
|
s.summary = %q{Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.}
|
44
49
|
s.test_files = [
|
45
50
|
"spec/geoipdb_spec.rb",
|
@@ -47,7 +52,6 @@ Gem::Specification.new do |s|
|
|
47
52
|
]
|
48
53
|
|
49
54
|
if s.respond_to? :specification_version then
|
50
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
55
|
s.specification_version = 3
|
52
56
|
|
53
57
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
data/lib/geoipdb.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
require 'geoipdb/geoipdb'
|
4
|
+
|
5
|
+
class IpInformation
|
6
|
+
attr_accessor :country_iso_code
|
7
|
+
attr_accessor :city_code
|
8
|
+
attr_accessor :city_name
|
9
|
+
attr_accessor :lat
|
10
|
+
attr_accessor :lng
|
11
|
+
attr_accessor :is_mobile
|
12
|
+
attr_accessor :isp_name
|
13
|
+
|
14
|
+
def mobile?
|
15
|
+
@is_mobile
|
16
|
+
end
|
17
|
+
end
|
data/sample_data/ip_ranges.csv
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
start_ip
|
2
|
-
0.0.0.0
|
3
|
-
0.0.1.0
|
4
|
-
1.0.0.0
|
5
|
-
1.0.1.0
|
6
|
-
1.1.1.0
|
7
|
-
1.1.2.0
|
8
|
-
1.2.3.0
|
9
|
-
1.2.4.0
|
10
|
-
1.4.0.0
|
11
|
-
1.4.1.0
|
1
|
+
start_ip,end_ip,field 4,field 13,
|
2
|
+
0.0.0.0,0.0.0.255,mobile,0
|
3
|
+
0.0.1.0,0.255.255.255,mobile,1,asdf,
|
4
|
+
1.0.0.0,1.0.0.255,xdsl,2,vodafone
|
5
|
+
1.0.1.0,1.1.0.255,wireless,3,
|
6
|
+
1.1.1.0,1.1.1.255,mobile,4,1vodafone2vodafone3vodafone4vodafone5vodafone1vodafone2vodafone3vodafone4vodafone5vodafone1vodafone2vodafone3vodafone4vodafone5vodafone1vodafone2vodafone3vodafone4vodafone5vodafone
|
7
|
+
1.1.2.0,1.2.2.255,mobile,5,
|
8
|
+
1.2.3.0,1.2.3.255,mobile,5,
|
9
|
+
1.2.4.0,1.3.255.255,mobile,2,
|
10
|
+
1.4.0.0,1.4.0.255,mobile,5,
|
11
|
+
1.4.1.0,1.8.255.255,mobile,3,
|
@@ -1,20 +1,20 @@
|
|
1
1
|
|
2
2
|
|
3
3
|
|
4
|
-
start_ip
|
5
|
-
0.0.0.0
|
4
|
+
start_ip,end_ip,field 13,
|
5
|
+
0.0.0.0,0.0.0.255,0,
|
6
6
|
|
7
|
-
0.0.1.0
|
7
|
+
0.0.1.0,0.255.255.255,1,
|
8
8
|
|
9
|
-
1.0.0.0
|
9
|
+
1.0.0.0,1.0.0.255,2,
|
10
10
|
|
11
|
-
1.0.1.0
|
11
|
+
1.0.1.0,1.1.0.255,3,
|
12
12
|
|
13
13
|
asfdasdf asdf asfasdfasdf§$%&/
|
14
14
|
|
15
|
-
1,
|
16
|
-
1.1.2.0
|
17
|
-
1.2.3.0
|
18
|
-
1.2.4.0
|
19
|
-
1.4.0.0
|
20
|
-
1.4.1.0
|
15
|
+
1, , , 7 ,.1.1.0,1.1.1.255,4,
|
16
|
+
1.1.2.0,1.2.2.255,5,
|
17
|
+
1.2.3.0,1.2.3.255,5,
|
18
|
+
1.2.4.0,1.3.255.255,2,
|
19
|
+
1.4.0.0,1.4.0.255,5,
|
20
|
+
1.4.1.0,1.8.255.255,3,
|
data/spec/geoipdb_spec.rb
CHANGED
@@ -1,37 +1,57 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__)+'/spec_helper')
|
2
2
|
|
3
3
|
|
4
|
-
describe
|
4
|
+
describe GeoIpDb do
|
5
|
+
|
6
|
+
CACHE_FILE = 'sample_data/ipdb.cache'
|
7
|
+
|
5
8
|
def init_db
|
6
|
-
@db = GeoIpDb.init './sample_data/cities.csv', './sample_data/ip_ranges.csv',
|
7
|
-
end
|
9
|
+
@db = GeoIpDb.init './sample_data/cities.csv', './sample_data/ip_ranges.csv', CACHE_FILE
|
10
|
+
end
|
8
11
|
|
9
|
-
|
10
|
-
@
|
12
|
+
it "should not throw an exception fault if data is corrupt" do
|
13
|
+
@db = GeoIpDb.init './sample_data/cities_corrupt.csv', './sample_data/ip_ranges_corrupt.csv', CACHE_FILE
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not init a db object if data files are missing" do
|
17
|
+
GeoIpDb.init( './sample_data/bla.csv', './sample_data/blubb.csv', CACHE_FILE ).should be_nil
|
11
18
|
end
|
12
19
|
|
13
20
|
it "should init correctly with sample data and create the cache-file" do
|
14
21
|
init_db
|
15
22
|
@db.should_not be_nil
|
16
|
-
File.exist?(
|
23
|
+
File.exist?(CACHE_FILE).should be_true
|
17
24
|
end
|
18
25
|
|
19
26
|
it "sould find the sample cities correcty" do
|
20
27
|
init_db
|
21
28
|
#afg,no region,kabul,-1,3,34.5167,69.1833
|
22
|
-
@db.
|
29
|
+
info = @db.information_for_ip "1.1.0.254"
|
30
|
+
info.city_code.should == 3
|
31
|
+
info.city_name.should == 'kabul'
|
32
|
+
info.country_iso_code.should == 'af'
|
33
|
+
info.lat.should == 34.5167
|
34
|
+
info.lng.should == 69.1833
|
35
|
+
info.should_not be_mobile
|
23
36
|
end
|
24
37
|
|
25
|
-
it
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
38
|
+
it 'should return correct is_mobile information' do
|
39
|
+
init_db
|
40
|
+
@db.information_for_ip("1.0.0.1").should_not be_mobile
|
41
|
+
@db.information_for_ip("1.1.1.1").should be_mobile
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return correct isp_name in ip_information' do
|
45
|
+
init_db
|
46
|
+
@db.information_for_ip("1.0.0.1").isp_name.should == :vodafone
|
47
|
+
@db.information_for_ip("1.1.1.1").isp_name.should == "1vodafone2vodafone3vodafone4vodafone5vodafone1vodafone2vodafone3vodafone4vodafone5vodafone1vodafone2vodafone3vodafone4vodafone5vodafone1vodafone2vodafone3vodafone4vodafone5vodafone"[0..99].to_sym
|
48
|
+
@db.information_for_ip("1.2.1.1").isp_name.should == nil
|
31
49
|
end
|
32
50
|
|
51
|
+
it "should write and read the cachefile correctly"
|
33
52
|
|
34
53
|
after :each do
|
35
|
-
File.unlink
|
54
|
+
File.unlink CACHE_FILE if File.exist? CACHE_FILE
|
36
55
|
end
|
56
|
+
|
37
57
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'ext'))
|
2
2
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
3
4
|
require 'rspec'
|
4
|
-
require 'geoipdb'
|
5
|
+
require 'lib/geoipdb'
|
5
6
|
|
6
7
|
# Requires supporting files with custom matchers and macros, etc,
|
7
8
|
# in ./support/ and its subdirectories.
|
data/test.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'ext'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'lib/geoipdb'
|
5
|
+
|
6
|
+
|
7
|
+
db = GeoIpDb.init 'ext/data/cities.csv', 'ext/data/ip_ranges.csv', 'ext/data/ipdb.cache'
|
8
|
+
|
9
|
+
puts db.information_for_ip("165.193.245.54").inspect
|
metadata
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: geoipdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 3
|
8
9
|
- 1
|
9
|
-
|
10
|
-
version: 0.1.4
|
10
|
+
version: 0.3.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Eugen Martin
|
14
|
+
- Martin Karlsch
|
14
15
|
autorequire:
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2011-
|
19
|
+
date: 2011-06-14 00:00:00 +02:00
|
19
20
|
default_executable:
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
23
|
+
name: rspec
|
23
24
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
25
|
none: false
|
25
26
|
requirements:
|
@@ -31,11 +32,11 @@ dependencies:
|
|
31
32
|
- 1
|
32
33
|
- 0
|
33
34
|
version: 2.1.0
|
34
|
-
requirement: *id001
|
35
35
|
prerelease: false
|
36
|
-
name: rspec
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
36
|
type: :development
|
37
|
+
requirement: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: bundler
|
39
40
|
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
41
|
none: false
|
41
42
|
requirements:
|
@@ -47,11 +48,11 @@ dependencies:
|
|
47
48
|
- 0
|
48
49
|
- 0
|
49
50
|
version: 1.0.0
|
50
|
-
requirement: *id002
|
51
51
|
prerelease: false
|
52
|
-
name: bundler
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
52
|
type: :development
|
53
|
+
requirement: *id002
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: jeweler
|
55
56
|
version_requirements: &id003 !ruby/object:Gem::Requirement
|
56
57
|
none: false
|
57
58
|
requirements:
|
@@ -63,11 +64,11 @@ dependencies:
|
|
63
64
|
- 5
|
64
65
|
- 1
|
65
66
|
version: 1.5.1
|
66
|
-
requirement: *id003
|
67
67
|
prerelease: false
|
68
|
-
name: jeweler
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
68
|
type: :development
|
69
|
+
requirement: *id003
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rcov
|
71
72
|
version_requirements: &id004 !ruby/object:Gem::Requirement
|
72
73
|
none: false
|
73
74
|
requirements:
|
@@ -77,15 +78,15 @@ dependencies:
|
|
77
78
|
segments:
|
78
79
|
- 0
|
79
80
|
version: "0"
|
80
|
-
requirement: *id004
|
81
81
|
prerelease: false
|
82
|
-
|
83
|
-
|
82
|
+
type: :development
|
83
|
+
requirement: *id004
|
84
|
+
description: Returns a GeoLocation and additional information for given IP. Reads Data from CSV-Files and uses internal binary caching.
|
84
85
|
email: eugeniusmartinus@googlemail.com
|
85
86
|
executables: []
|
86
87
|
|
87
88
|
extensions:
|
88
|
-
- ext/extconf.rb
|
89
|
+
- ext/geoipdb/extconf.rb
|
89
90
|
extra_rdoc_files:
|
90
91
|
- LICENSE.txt
|
91
92
|
- README.markdown
|
@@ -97,12 +98,12 @@ files:
|
|
97
98
|
- README.markdown
|
98
99
|
- Rakefile
|
99
100
|
- VERSION
|
100
|
-
- ext/
|
101
|
-
- ext/
|
102
|
-
- ext/geoipdb.
|
103
|
-
- ext/
|
104
|
-
- ext/ipdb.
|
105
|
-
- ext/
|
101
|
+
- ext/geoipdb/Makefile
|
102
|
+
- ext/geoipdb/build.sh
|
103
|
+
- ext/geoipdb/extconf.rb
|
104
|
+
- ext/geoipdb/geoipdb.c
|
105
|
+
- ext/geoipdb/ipdb.c
|
106
|
+
- ext/geoipdb/ipdb.h
|
106
107
|
- geoipdb.gemspec
|
107
108
|
- lib/geoipdb.rb
|
108
109
|
- sample_data/cities.csv
|
@@ -111,14 +112,16 @@ files:
|
|
111
112
|
- sample_data/ip_ranges_corrupt.csv
|
112
113
|
- spec/geoipdb_spec.rb
|
113
114
|
- spec/spec_helper.rb
|
115
|
+
- test.rb
|
114
116
|
has_rdoc: true
|
115
|
-
homepage: http://github.com/
|
117
|
+
homepage: http://github.com/madvertise/geoipdb
|
116
118
|
licenses:
|
117
119
|
- MIT
|
118
120
|
post_install_message:
|
119
121
|
rdoc_options: []
|
120
122
|
|
121
123
|
require_paths:
|
124
|
+
- lib
|
122
125
|
- ext
|
123
126
|
required_ruby_version: !ruby/object:Gem::Requirement
|
124
127
|
none: false
|
@@ -141,7 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
144
|
requirements: []
|
142
145
|
|
143
146
|
rubyforge_project:
|
144
|
-
rubygems_version: 1.
|
147
|
+
rubygems_version: 1.5.3
|
145
148
|
signing_key:
|
146
149
|
specification_version: 3
|
147
150
|
summary: Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.
|
data/ext/extconf.rb
DELETED
data/ext/geoipdb.c
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
#include "ipdb.h"
|
2
|
-
|
3
|
-
#include "ruby.h"
|
4
|
-
|
5
|
-
/**
|
6
|
-
Ruby Wrapper
|
7
|
-
*/
|
8
|
-
|
9
|
-
typedef struct geipdb {
|
10
|
-
IPDB *db;
|
11
|
-
} geoipdb;
|
12
|
-
|
13
|
-
static VALUE cGeoIpDb;
|
14
|
-
|
15
|
-
VALUE method_hello_world(VALUE self);
|
16
|
-
|
17
|
-
// free the memory used by the db, called by the Ruby-GC
|
18
|
-
void geoipdb_free(geoipdb *gi) {
|
19
|
-
printf("Freeing memory for the GeoIpDb.. \n");
|
20
|
-
if(gi == NULL)
|
21
|
-
return;
|
22
|
-
if (gi->db != NULL){
|
23
|
-
if(gi->db->cities != NULL ){
|
24
|
-
printf("..freeing cities \n");
|
25
|
-
free(gi->db->cities);
|
26
|
-
gi->db->cities = NULL;
|
27
|
-
}
|
28
|
-
if(gi->db->ranges != NULL ){
|
29
|
-
printf("..freeing ranges \n");
|
30
|
-
free(gi->db->ranges);
|
31
|
-
gi->db->ranges = NULL;
|
32
|
-
}
|
33
|
-
if(gi->db != NULL){
|
34
|
-
printf("..freeing ipdb \n");
|
35
|
-
free(gi->db);
|
36
|
-
}
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
|
-
|
41
|
-
VALUE ipdb_init(VALUE self, VALUE cities_file_name, VALUE ranges_file_name, VALUE cache_file_name) {
|
42
|
-
geoipdb *gi;
|
43
|
-
|
44
|
-
Check_Type(cities_file_name, T_STRING);
|
45
|
-
Check_Type(ranges_file_name, T_STRING);
|
46
|
-
Check_Type(cache_file_name, T_STRING);
|
47
|
-
|
48
|
-
char *cities_csv_file = RSTRING(cities_file_name)->ptr;
|
49
|
-
char *ranges_csv_file = RSTRING(ranges_file_name)->ptr;
|
50
|
-
char *cache_file = RSTRING(cache_file_name)->ptr;
|
51
|
-
|
52
|
-
gi = malloc(sizeof(geoipdb));
|
53
|
-
|
54
|
-
gi->db= init_db(cities_csv_file, ranges_csv_file, cache_file);
|
55
|
-
|
56
|
-
if(gi->db == NULL)
|
57
|
-
{
|
58
|
-
if(DEBUG)
|
59
|
-
printf("Could not init DB!\n");
|
60
|
-
/*
|
61
|
-
TODO: Add geoipdb_free in this case.. though not important for production...
|
62
|
-
*/
|
63
|
-
return Qnil;
|
64
|
-
}else{
|
65
|
-
if(DEBUG)
|
66
|
-
printf("\nDB Init completed!\n");
|
67
|
-
return(Data_Wrap_Struct(cGeoIpDb, 0, geoipdb_free, gi));
|
68
|
-
}
|
69
|
-
}
|
70
|
-
|
71
|
-
|
72
|
-
VALUE city_to_hash(City * city){
|
73
|
-
VALUE hash = rb_hash_new();
|
74
|
-
// return a ruby-hash with the needed data
|
75
|
-
rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(city->name));
|
76
|
-
rb_hash_aset(hash, rb_str_new2("country"), rb_str_new2(city->country_iso2));
|
77
|
-
rb_hash_aset(hash, rb_str_new2("lat"), rb_float_new(city->lat));
|
78
|
-
rb_hash_aset(hash, rb_str_new2("lng"), rb_float_new(city->lng));
|
79
|
-
rb_hash_aset(hash, rb_str_new2("city_code"), INT2FIX(city->city_code));
|
80
|
-
return hash;
|
81
|
-
}
|
82
|
-
|
83
|
-
VALUE ipdb_city_by_ip(VALUE self, VALUE ip_string){
|
84
|
-
char *ip = RSTRING(ip_string)->ptr;
|
85
|
-
geoipdb *gi;
|
86
|
-
|
87
|
-
Data_Get_Struct(self, geoipdb, gi);
|
88
|
-
City * city = city_by_ip(gi->db, ip);
|
89
|
-
if(city == NULL)
|
90
|
-
{
|
91
|
-
// printf("Could not find city for ip: %s\n", ip);
|
92
|
-
return Qnil;
|
93
|
-
}else{
|
94
|
-
// printf("Found city for ip: %s\n", ip);
|
95
|
-
// print_city(city);
|
96
|
-
return city_to_hash(city);
|
97
|
-
// create a hash to return to ruby:
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
void Init_geoipdb(void)
|
104
|
-
{
|
105
|
-
//Erstelle die Klasse cGeoIpDb als Subklasse von Object
|
106
|
-
cGeoIpDb = rb_define_class( "GeoIpDb", rb_cObject);
|
107
|
-
rb_define_singleton_method( cGeoIpDb, "init", ipdb_init, 3);
|
108
|
-
rb_define_method( cGeoIpDb, "city_by_ip", ipdb_city_by_ip, 1);
|
109
|
-
}
|
data/ext/test.c
DELETED
@@ -1,42 +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
|
-
|
10
|
-
|
11
|
-
int main() {
|
12
|
-
IPDB * db = init_db("data/cities.csv", "data/ip_ranges.csv", "data/ipdb.cache");
|
13
|
-
// IPDB * db = init_db(NULL, NULL, NULL);
|
14
|
-
|
15
|
-
|
16
|
-
// City * city;
|
17
|
-
//
|
18
|
-
// // city = city_by_ip(db, "1.16.0.0");
|
19
|
-
// int i;
|
20
|
-
int count = 10000000;
|
21
|
-
|
22
|
-
benchmark_search(db, count);
|
23
|
-
|
24
|
-
// for(i = 0; i < count; ++i)
|
25
|
-
// {
|
26
|
-
// if(i % 100000 == 0)
|
27
|
-
// printf("Working: i= %i \n", i);
|
28
|
-
//
|
29
|
-
// city = city_by_ip(db, "91.44.93.35");
|
30
|
-
// }
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
//
|
37
|
-
int * response;
|
38
|
-
scanf("%i",response);
|
39
|
-
|
40
|
-
return 0;
|
41
|
-
|
42
|
-
}
|