sumdog-geoip 0.7.3

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.
Files changed (6) hide show
  1. data/README.md +160 -0
  2. data/Rakefile +55 -0
  3. data/extconf.rb +13 -0
  4. data/geoip.c +426 -0
  5. data/test.rb +226 -0
  6. metadata +55 -0
data/README.md ADDED
@@ -0,0 +1,160 @@
1
+ Ruby GeoIP Bindings
2
+ =======================
3
+
4
+ What?
5
+ -----
6
+
7
+ This is a library which provides a single function. The function takes as
8
+ input an IP address and it outputs a hash containing best-guess geographical
9
+ information (like city, country, latitude, and longitude).
10
+
11
+ Actually this is only a Ruby binding to a C library which provides this
12
+ function. Also, you must download a large binary database with all this
13
+ mapping information. It is kindly provided free of charge by MaxMind.com.
14
+
15
+ Usage
16
+
17
+ require 'geoip'
18
+ db = GeoIP::City.new('/opt/GeoIP/share/GeoIP/GeoLiteCity.dat')
19
+ result = db.look_up('24.24.24.24')
20
+ p result
21
+ # => {:city=>"Ithaca",
22
+ # :latitude=>42.4277992248535,
23
+ # :longitude=>-76.4981994628906,
24
+ # :country_code3=>"USA",
25
+ # :country_code=>"US",
26
+ # :country_name=>"United States",
27
+ # :dma_code=>555,
28
+ # :area_code=>607,
29
+ # :region=>"NY" }
30
+
31
+ There are arguments to database initializer.
32
+
33
+ 1. The first argument is the filename of the GeoIPCity.dat file
34
+
35
+ 2. The second argument (optional) is to specify how GeoIP should
36
+ keep the database in memory. There are three possibilities
37
+
38
+ * `:filesystem` -- Read database from filesystem, uses least memory.
39
+
40
+ * `:index` -- The most frequently accessed index portion of the
41
+ database, resulting in faster lookups than :filesystem, but less
42
+ memory usage than :memory.
43
+
44
+ * `:memory` -- (Default.) Load database into memory, faster performance but uses more memory.
45
+
46
+ 3. The third argument is boolean and decides whether the system should
47
+ reload the database if changes are made to the dat file. (You probably
48
+ don't need this. Default: false.)
49
+
50
+ For example
51
+
52
+ GeoIP::City.new(dbfile, :filesystem, true)
53
+
54
+ Usage for Organization Search
55
+ -----------------------------
56
+
57
+ require 'geoip'
58
+ db = GeoIP::Organization.new('/opt/GeoIP/share/GeoIP/GeoIPOrg.dat')
59
+ db.look_up('24.24.24.24')
60
+ # => {:name=>"Road Runner"}
61
+
62
+ The name is the only data available for Organizations.
63
+
64
+ Install
65
+ -------
66
+
67
+ Some variation of the following should work.
68
+
69
+ 1. Install the GeoCity C library. You can get it from
70
+ [MaxMind](http://www.maxmind.com/app/c).
71
+ For example, I like to install mine in `/opt/GeoIP`, so I do this:
72
+
73
+ tar -zxvf GeoIP-1.4.3.tar.gz
74
+ cd GeoIP-1.4.3
75
+ ./configure --prefix=/opt/GeoIP
76
+ make && sudo make install
77
+
78
+ On Mac OS X, you can install using [homebrew](http://github.com/mxcl/homebrew):
79
+
80
+ brew install geoip
81
+
82
+ Linux platforms utilizing Apt have several packages available:
83
+
84
+ geoip-bin
85
+ geoip-database
86
+ libgeoip-dev
87
+
88
+ 2. Now install the `geoip` gem
89
+
90
+ gem install geoip-c -- --with-geoip-dir=/opt/GeoIP
91
+
92
+ Alternatively, if you installed libgeoip using homebrew:
93
+
94
+ gem install geoip-c
95
+
96
+ 3. Download the GeoLite City database file in binary format at http://www.maxmind.com/app/geolitecity
97
+ Maybe this [direct link](http://www.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz) will work.
98
+ I put this file in
99
+
100
+ /opt/GeoIP/share/GeoIP/GeoLiteCity.dat
101
+
102
+ If you installed libgeoip using homebrew then put it in:
103
+
104
+ /opt/local/share/GeoIP/GeoLiteCity.dat
105
+
106
+ If you are a paying customer, you will download the files required below:
107
+
108
+ [MaxMind Customer Downloads](http://www.maxmind.com/app/download_files)
109
+
110
+ You will want to get the City Rev1 data file and Organization files at minimum.
111
+
112
+ 4. Use it!
113
+
114
+ See above for usage details.
115
+
116
+ Hints
117
+ -----
118
+
119
+ 1. Might need to set
120
+
121
+ export ARCHFLAGS="-arch i386"
122
+
123
+ to be able to compile the gem.
124
+
125
+ Example:
126
+
127
+ env ARCHFLAGS="-arch i386" gem install geoip-c -- --with-geoip-dir=/opt/GeoIP
128
+
129
+ 2. You might find [this shell script](http://github.com/grimen/my_shell_scripts/blob/8cf04cb6829e68a47f2d6f9d9e057766ea72beb4/install_geoip-city.sh)
130
+ helpful to install the C library.
131
+
132
+ Links
133
+ -----
134
+
135
+ This iteration of the library is based on the hard work of Ryah Dahl (ry@tinyclouds.org). You can find the original RDocs and Git Repo below:
136
+
137
+ [rdocs](http://geoip-city.rubyforge.org/)
138
+ [git repo](https://github.com/ry/geoip-city/tree)
139
+
140
+ Thanks
141
+ ------
142
+
143
+ Special appreciation and thanks belongs to Ry Dahl for his initial work on this library.
144
+
145
+ Many thanks to our contributors:
146
+
147
+ * Charles Brian Quinn ([seebq](https://github.com/seebq))
148
+ * Michael Sheakoski
149
+ * Silvio Quadri
150
+ * Leonardo Almeida ([leogalmeida](https://github.com/leogalmeida))
151
+
152
+ License
153
+ -------
154
+ Copyright (C) 2007--2009 Ryah Dahl (ry@tinyclouds.org), Matt Todd (mtodd@highgroove.com)
155
+
156
+ This program is free software. It comes without any warranty, to
157
+ the extent permitted by applicable law. You can redistribute it
158
+ and/or modify it under the terms of the Do What The Fuck You Want
159
+ To Public License, Version 2, as published by Sam Hocevar. See
160
+ http://sam.zoy.org/wtfpl/COPYING for more details.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+
7
+ task :default => [:compile, :test]
8
+
9
+ CLEAN.add "geoip.{o,bundle,so,obj,pdb,lib,def,exp}"
10
+ CLOBBER.add ['Makefile', 'mkmf.log','doc']
11
+
12
+ Rake::RDocTask.new do |rdoc|
13
+ rdoc.rdoc_files.add ['README', 'geoip.c']
14
+ rdoc.main = "README" # page to start on
15
+ rdoc.rdoc_dir = 'doc/' # rdoc output folder
16
+ end
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.test_files = 'test.rb'
20
+ t.verbose = true
21
+ end
22
+
23
+ spec = Gem::Specification.new do |s|
24
+ s.name = 'sumdog-geoip'
25
+ s.version = "0.7.3"
26
+
27
+ s.authors = ['Ryah Dahl', 'Matt Todd', 'Mat Byczkowski']
28
+ s.email = 'mbyczkowski@gmail.com'
29
+
30
+ s.summary = "A Binding to the GeoIP C library"
31
+ s.description = 'Generic GeoIP lookup tool. Based on the geoip-c RubyGem by Matt Todd'
32
+ s.homepage = "http://github.com/mtodd/geoip"
33
+
34
+ s.files = ["Rakefile", "extconf.rb", "test.rb", "geoip.c", "README.md"]
35
+ s.test_files = 'test.rb'
36
+ s.extensions = 'extconf.rb'
37
+ s.require_path = '.'
38
+ end
39
+
40
+ Rake::GemPackageTask.new(spec) do |p|
41
+ p.need_tar = true
42
+ p.gem_spec = spec
43
+ end
44
+
45
+ desc 'compile the extension'
46
+ task(:compile => 'Makefile') { sh 'make' }
47
+ file('Makefile' => "geoip.c") { ruby 'extconf.rb' }
48
+
49
+ task :install => [:gem] do
50
+ `env ARCHFLAGS="-arch i386" gem install pkg/sumdog-geoip-0.7.3.gem -- --with-geoip-dir=/usr/local/GeoIP`
51
+ end
52
+
53
+ task(:webpage) do
54
+ sh 'scp -r doc/* rydahl@rubyforge.org:/var/www/gforge-projects/geoip-city/'
55
+ end
data/extconf.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("geoip")
4
+
5
+ unless have_func('iconv_open', 'iconv.h') or have_library('iconv', 'iconv_open', 'iconv.h')
6
+ abort "you must have iconv library installed!"
7
+ end
8
+
9
+ if have_library('GeoIP', 'GeoIP_record_by_ipnum') and have_header('GeoIPCity.h')
10
+ create_makefile('geoip')
11
+ else
12
+ abort("you must have geoip c library installed!")
13
+ end
data/geoip.c ADDED
@@ -0,0 +1,426 @@
1
+ /* ry dahl <ry@tinyclouds.org> May 21, 2007 */
2
+ /* Matt Todd <mtodd@highgroove.com> June 4, 2009 */
3
+ /* This program is free software. It comes without any warranty, to
4
+ * the extent permitted by applicable law. You can redistribute it
5
+ * and/or modify it under the terms of the Do What The Fuck You Want
6
+ * To Public License, Version 2, as published by Sam Hocevar. See
7
+ * http://sam.zoy.org/wtfpl/COPYING for more details. */
8
+ #include <ruby.h>
9
+ #include <GeoIP.h>
10
+ #include <GeoIPCity.h>
11
+ #include "iconv.h"
12
+
13
+ static VALUE mGeoIP;
14
+ static VALUE mGeoIP_City;
15
+ static VALUE mGeoIP_Country;
16
+ static VALUE mGeoIP_Organization;
17
+ static VALUE mGeoIP_Region;
18
+ static VALUE mGeoIP_ISP;
19
+ static VALUE mGeoIP_NetSpeed;
20
+ static VALUE mGeoIP_Domain;
21
+ static VALUE rb_geoip_memory;
22
+ static VALUE rb_geoip_filesystem;
23
+ static VALUE rb_geoip_index;
24
+
25
+ /* helpers */
26
+ void rb_hash_sset(VALUE hash, const char *str, VALUE v) {
27
+ rb_hash_aset(hash, ID2SYM(rb_intern(str)), v);
28
+ }
29
+
30
+ /* pulled from http://blog.inventic.eu/?p=238 and
31
+ https://github.com/Vagabond/erlang-iconv/blob/master/c_src/iconv_drv.c */
32
+ static VALUE encode_to_utf8_and_return_rb_str(char *value) {
33
+ char dst[BUFSIZ];
34
+ size_t srclen = strlen(value);
35
+ size_t dstlen = srclen * 2;
36
+
37
+ char * pIn = value;
38
+ char * pOut = ( char*)dst;
39
+
40
+ iconv_t cd = iconv_open("UTF-8","ISO-8859-1");
41
+ iconv(cd, &pIn, &srclen, &pOut, &dstlen);
42
+ iconv_close(cd);
43
+
44
+ *(pOut++) = 0; /* ensure we null terminate */
45
+
46
+ return rb_str_new2(dst);
47
+ }
48
+
49
+ int check_load_option(VALUE load_option) {
50
+ if(load_option == rb_geoip_memory) {
51
+ return GEOIP_MEMORY_CACHE;
52
+ } else if(load_option == rb_geoip_filesystem) {
53
+ return GEOIP_STANDARD;
54
+ } else if(load_option == rb_geoip_index) {
55
+ return GEOIP_INDEX_CACHE;
56
+ } else {
57
+ rb_raise(rb_eTypeError, "the second option must be :memory, :filesystem, or :index");
58
+ return Qnil;
59
+ }
60
+ }
61
+
62
+ /* Generic initializer */
63
+ static VALUE rb_geoip_database_new(VALUE mGeoIP_Database_Class, int argc, VALUE *argv, VALUE self)
64
+ {
65
+ GeoIP *gi;
66
+ VALUE database = Qnil;
67
+ VALUE filename, load_option = Qnil, check_cache = Qnil;
68
+ int flag;
69
+
70
+ rb_scan_args(argc, argv, "12", &filename, &load_option, &check_cache);
71
+ if(NIL_P(load_option))
72
+ load_option = rb_geoip_memory;
73
+ if(NIL_P(check_cache))
74
+ check_cache = Qfalse;
75
+ Check_Type(load_option, T_SYMBOL);
76
+
77
+ if(flag = check_load_option(load_option)) flag;
78
+
79
+ if(RTEST(check_cache)) flag |= GEOIP_CHECK_CACHE;
80
+
81
+ if(gi = GeoIP_open(StringValuePtr(filename), flag)) {
82
+ database = Data_Wrap_Struct(mGeoIP_Database_Class, 0, GeoIP_delete, gi);
83
+ rb_obj_call_init(database, 0, 0);
84
+ } else {
85
+ rb_sys_fail("Problem opening database");
86
+ }
87
+ return database;
88
+ }
89
+
90
+ /* Generic, single-value look up method */
91
+ static VALUE generic_single_value_lookup_response(char *key, char *value)
92
+ {
93
+ VALUE result = rb_hash_new();
94
+ if(value) {
95
+ rb_hash_sset(result, key, encode_to_utf8_and_return_rb_str(value));
96
+ return result;
97
+ } else {
98
+ return Qnil;
99
+ }
100
+ }
101
+
102
+ /* GeoIP::City ***************************************************************/
103
+
104
+ VALUE rb_city_record_to_hash(GeoIPRecord *record)
105
+ {
106
+ VALUE hash = rb_hash_new();
107
+
108
+ if(record->country_code)
109
+ rb_hash_sset(hash, "country_code", encode_to_utf8_and_return_rb_str(record->country_code));
110
+ if(record->country_code3)
111
+ rb_hash_sset(hash, "country_code3", encode_to_utf8_and_return_rb_str(record->country_code3));
112
+ if(record->country_name)
113
+ rb_hash_sset(hash, "country_name", encode_to_utf8_and_return_rb_str(record->country_name));
114
+ if(record->region)
115
+ rb_hash_sset(hash, "region", encode_to_utf8_and_return_rb_str(record->region));
116
+ if(record->city)
117
+ rb_hash_sset(hash, "city", encode_to_utf8_and_return_rb_str(record->city));
118
+ if(record->postal_code)
119
+ rb_hash_sset(hash, "postal_code", encode_to_utf8_and_return_rb_str(record->postal_code));
120
+ if(record->latitude)
121
+ rb_hash_sset(hash, "latitude", rb_float_new((double)record->latitude));
122
+ if(record->longitude)
123
+ rb_hash_sset(hash, "longitude", rb_float_new((double)record->longitude));
124
+ if(record->dma_code)
125
+ rb_hash_sset(hash, "dma_code", INT2NUM(record->dma_code));
126
+ if(record->area_code)
127
+ rb_hash_sset(hash, "area_code", INT2NUM(record->area_code));
128
+
129
+ return hash;
130
+ }
131
+
132
+ /* The first argument is the filename of the GeoIPCity.dat file
133
+ * load_option = :standard, :index, or :memory. default :memory
134
+ * check_cache = true or false. default false
135
+ *
136
+ * filesystem: read database from filesystem, uses least memory.
137
+ *
138
+ * index: the most frequently accessed index portion of the database,
139
+ * resulting in faster lookups than :filesystem, but less memory usage than
140
+ * :memory.
141
+ *
142
+ * memory: load database into memory, faster performance but uses more
143
+ * memory.
144
+ */
145
+ static VALUE rb_geoip_city_new(int argc, VALUE *argv, VALUE self)
146
+ {
147
+ return rb_geoip_database_new(mGeoIP_City, argc, argv, self);
148
+ }
149
+
150
+ /* Pass this function an IP address as a string, it will return a hash
151
+ * containing all the information that the database knows about the IP
152
+ * db.look_up('24.24.24.24')
153
+ * => {:city=>"Ithaca", :latitude=>42.4277992248535,
154
+ * :country_code=>"US", :longitude=>-76.4981994628906,
155
+ * :country_code3=>"USA", :dma_code=>555,
156
+ * :country_name=>"United States", :area_code=>607,
157
+ * :region=>"NY"}
158
+ */
159
+ VALUE rb_geoip_city_look_up(VALUE self, VALUE addr) {
160
+ GeoIP *gi;
161
+ GeoIPRecord *record = NULL;
162
+ VALUE hash = Qnil;
163
+
164
+ Check_Type(addr, T_STRING);
165
+ Data_Get_Struct(self, GeoIP, gi);
166
+ if(record = GeoIP_record_by_addr(gi, StringValuePtr(addr))) {
167
+ hash = rb_city_record_to_hash(record);
168
+ GeoIPRecord_delete(record);
169
+ }
170
+ return hash;
171
+ }
172
+
173
+ /* GeoIP::Country ************************************************************/
174
+
175
+ /* GeoIP::Country.new('/path/to/GeoIPCountry.dat')
176
+ * load_option is not required for this database because it is ignored.
177
+ */
178
+ static VALUE rb_geoip_country_new(int argc, VALUE *argv, VALUE self)
179
+ {
180
+ return rb_geoip_database_new(mGeoIP_Country, argc, argv, self);
181
+ }
182
+
183
+ /* Pass this function an IP address as a string, it will return a hash
184
+ * containing all the information that the database knows about the IP
185
+ * db.look_up('24.24.24.24')
186
+ * => {:country_code=>"US",
187
+ * :country_code3=>"USA",
188
+ * :country_name=>"United States"}
189
+ */
190
+ VALUE rb_geoip_country_look_up(VALUE self, VALUE addr) {
191
+ GeoIP *gi;
192
+ VALUE hash = Qnil;
193
+ int country_id;
194
+
195
+ Check_Type(addr, T_STRING);
196
+ Data_Get_Struct(self, GeoIP, gi);
197
+ country_id = GeoIP_id_by_addr(gi, StringValuePtr(addr));
198
+ if(country_id < 1) return Qnil;
199
+
200
+ hash = rb_hash_new();
201
+ rb_hash_sset(hash, "country_code", rb_str_new2(GeoIP_country_code[country_id]));
202
+ rb_hash_sset(hash, "country_code3", rb_str_new2(GeoIP_country_code3[country_id]));
203
+ rb_hash_sset(hash, "country_name", rb_str_new2(GeoIP_country_name[country_id]));
204
+
205
+ return hash;
206
+ }
207
+
208
+ /* GeoIP::Organization *******************************************************/
209
+
210
+ /* GeoIP::Organization.new('/path/to/GeoIPOrg.dat', load_option)
211
+ * load_option can be:
212
+ * * :memory - load the data into memory, fastest (default)
213
+ * * :filesystem - look up from filesystem, least memory intensive
214
+ * * :index - stores in memory most recent queries
215
+ *
216
+ */
217
+ static VALUE rb_geoip_org_new(int argc, VALUE *argv, VALUE self)
218
+ {
219
+ return rb_geoip_database_new(mGeoIP_Organization, argc, argv, self);
220
+ }
221
+
222
+ /* Pass this function an IP address as a string, it will return a hash
223
+ * containing all the information that the database knows about the IP:
224
+ * db.look_up('24.24.24.24')
225
+ * => {:name => "Road Runner"}
226
+ */
227
+ VALUE rb_geoip_org_look_up(VALUE self, VALUE addr) {
228
+ GeoIP *gi;
229
+ Check_Type(addr, T_STRING);
230
+ Data_Get_Struct(self, GeoIP, gi);
231
+ return generic_single_value_lookup_response("name", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
232
+ }
233
+
234
+
235
+ /* GeoIP::Region ************************************************************/
236
+
237
+ /* GeoIP::Region.new('/path/to/GeoIPRegion.dat', load_option)
238
+ * load_option can be:
239
+ * * :memory - load the data into memory, fastest (default)
240
+ * * :filesystem - look up from filesystem, least memory intensive
241
+ * * :index - stores in memory most recent queries
242
+ */
243
+ static VALUE rb_geoip_region_new(int argc, VALUE *argv, VALUE self)
244
+ {
245
+ return rb_geoip_database_new(mGeoIP_Region, argc, argv, self);
246
+ }
247
+
248
+ /* Pass this function an IP address as a string, it will return a hash
249
+ * containing all the information that the database knows about the IP
250
+ * db.look_up('24.24.24.24')
251
+ * => {:country_code=>"US",
252
+ * :country_code3=>"USA",
253
+ * :country_name=>"United States"
254
+ * :region=>"NY"}
255
+ */
256
+ VALUE rb_geoip_region_look_up(VALUE self, VALUE addr) {
257
+ GeoIP *gi;
258
+ VALUE country, reg;
259
+ VALUE hash = Qnil;
260
+ GeoIPRegion *r;
261
+ int country_id;
262
+
263
+ hash = rb_hash_new();
264
+ Check_Type(addr, T_STRING);
265
+ Data_Get_Struct(self, GeoIP, gi);
266
+ r = GeoIP_region_by_addr(gi, StringValuePtr(addr));
267
+ if(r == NULL) return hash;
268
+
269
+ country_id = GeoIP_id_by_code(r->country_code);
270
+
271
+ rb_hash_sset(hash,"country_code", encode_to_utf8_and_return_rb_str(r->country_code));
272
+ rb_hash_sset(hash,"country_code3", encode_to_utf8_and_return_rb_str(GeoIP_code3_by_id(country_id)));
273
+ rb_hash_sset(hash,"country_name", encode_to_utf8_and_return_rb_str(GeoIP_name_by_id(country_id)));
274
+ rb_hash_sset(hash,"region", encode_to_utf8_and_return_rb_str(r->region));
275
+
276
+ GeoIPRegion_delete(r);
277
+ return hash;
278
+ }
279
+
280
+
281
+ /* GeoIP::ISP *******************************************************/
282
+
283
+ /* GeoIP::ISP.new('/path/to/GeoIPISP.dat', load_option)
284
+ * load_option can be:
285
+ * * :memory - load the data into memory, fastest (default)
286
+ * * :filesystem - look up from filesystem, least memory intensive
287
+ * * :index - stores in memory most recent queries
288
+ *
289
+ */
290
+ static VALUE rb_geoip_isp_new(int argc, VALUE *argv, VALUE self)
291
+ {
292
+ return rb_geoip_database_new(mGeoIP_ISP, argc, argv, self);
293
+ }
294
+
295
+ /* Pass this function an IP address as a string, it will return a hash
296
+ * containing all the information that the database knows about the IP:
297
+ * db.look_up('24.24.24.24')
298
+ * => {:isp => "Road Runner"}
299
+ */
300
+ VALUE rb_geoip_isp_look_up(VALUE self, VALUE addr) {
301
+ GeoIP *gi;
302
+ Check_Type(addr, T_STRING);
303
+ Data_Get_Struct(self, GeoIP, gi);
304
+ return generic_single_value_lookup_response("isp", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
305
+ }
306
+
307
+ /* GeoIP::NetSpeed *******************************************************/
308
+
309
+ /* GeoIP::NetSpeed.new('/path/to/GeoIPNetSpeed.dat', load_option)
310
+ * load_option can be:
311
+ * * :memory - load the data into memory, fastest (default)
312
+ * * :filesystem - look up from filesystem, least memory intensive
313
+ * * :index - stores in memory most recent queries
314
+ *
315
+ */
316
+ static VALUE rb_geoip_netspeed_new(int argc, VALUE *argv, VALUE self)
317
+ {
318
+ return rb_geoip_database_new(mGeoIP_NetSpeed, argc, argv, self);
319
+ }
320
+
321
+ /* Pass this function an IP address as a string, it will return a hash
322
+ * containing all the information that the database knows about the IP:
323
+ * db.look_up('24.24.24.24')
324
+ * => {:netspeed => "Cable/DSL"}
325
+ */
326
+ VALUE rb_geoip_netspeed_look_up(VALUE self, VALUE addr) {
327
+ GeoIP *gi;
328
+ Check_Type(addr, T_STRING);
329
+ Data_Get_Struct(self, GeoIP, gi);
330
+ return generic_single_value_lookup_response("netspeed", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
331
+ }
332
+
333
+ /* GeoIP::Domain *******************************************************/
334
+
335
+ /* GeoIP::Domain.new('/path/to/GeoIPDomain.dat', load_option)
336
+ * load_option can be:
337
+ * * :memory - load the data into memory, fastest (default)
338
+ * * :filesystem - look up from filesystem, least memory intensive
339
+ * * :index - stores in memory most recent queries
340
+ *
341
+ */
342
+ static VALUE rb_geoip_domain_new(int argc, VALUE *argv, VALUE self)
343
+ {
344
+ return rb_geoip_database_new(mGeoIP_Domain, argc, argv, self);
345
+ }
346
+
347
+ /* Pass this function an IP address as a string, it will return a hash
348
+ * containing all the information that the database knows about the IP:
349
+ * db.look_up('24.24.24.24')
350
+ * => {:domain => "rr.com"}
351
+ */
352
+ VALUE rb_geoip_domain_look_up(VALUE self, VALUE addr) {
353
+ GeoIP *gi;
354
+ Check_Type(addr, T_STRING);
355
+ Data_Get_Struct(self, GeoIP, gi);
356
+ return generic_single_value_lookup_response("domain", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
357
+ }
358
+
359
+ /* GeoIP *********************************************************************/
360
+
361
+ /* Returns the numeric form of an IP address.
362
+ *
363
+ * For example:
364
+ * 24.24.24.24 => 404232216
365
+ *
366
+ * This is used in order to be able to perform searches in CSV versions of the
367
+ * data files or in SQL records if the data has been put there.
368
+ */
369
+ VALUE rb_geoip_addr_to_num(VALUE self, VALUE addr) {
370
+ Check_Type(addr, T_STRING);
371
+ return UINT2NUM((unsigned int)_GeoIP_addr_to_num(StringValuePtr(addr)));
372
+ }
373
+
374
+ // Fixes a bug with 64bit architectures where this delcaration doesn't exist
375
+ // in the GeoIP library causing segmentation faults.
376
+ char *_GeoIP_num_to_addr(GeoIP* gi, unsigned long ipnum);
377
+
378
+ VALUE rb_geoip_num_to_addr(VALUE self, VALUE num) {
379
+ VALUE num_type = TYPE(num);
380
+ switch(num_type) {
381
+ case T_FIXNUM: break;
382
+ case T_BIGNUM: break;
383
+ default: rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Bignum)", rb_obj_classname(num));
384
+ }
385
+ return rb_str_new2((char*)_GeoIP_num_to_addr(NULL, (unsigned long)NUM2ULONG(num)));
386
+ }
387
+
388
+ void Init_geoip()
389
+ {
390
+ mGeoIP = rb_define_module("GeoIP");
391
+
392
+ rb_geoip_memory = ID2SYM(rb_intern("memory"));
393
+ rb_geoip_filesystem = ID2SYM(rb_intern("filesystem"));
394
+ rb_geoip_index = ID2SYM(rb_intern("index"));
395
+
396
+ mGeoIP_City = rb_define_class_under(mGeoIP, "City", rb_cObject);
397
+ rb_define_singleton_method(mGeoIP_City, "new", rb_geoip_city_new, -1);
398
+ rb_define_method( mGeoIP_City, "look_up", rb_geoip_city_look_up, 1);
399
+
400
+ mGeoIP_Country = rb_define_class_under(mGeoIP, "Country", rb_cObject);
401
+ rb_define_singleton_method(mGeoIP_Country, "new", rb_geoip_country_new, -1);
402
+ rb_define_method( mGeoIP_Country, "look_up", rb_geoip_country_look_up, 1);
403
+
404
+ mGeoIP_Organization = rb_define_class_under(mGeoIP, "Organization", rb_cObject);
405
+ rb_define_singleton_method(mGeoIP_Organization, "new", rb_geoip_org_new, -1);
406
+ rb_define_method( mGeoIP_Organization, "look_up", rb_geoip_org_look_up, 1);
407
+
408
+ mGeoIP_Region = rb_define_class_under(mGeoIP, "Region", rb_cObject);
409
+ rb_define_singleton_method(mGeoIP_Region, "new", rb_geoip_region_new, -1);
410
+ rb_define_method( mGeoIP_Region, "look_up", rb_geoip_region_look_up, 1);
411
+
412
+ mGeoIP_ISP = rb_define_class_under(mGeoIP, "ISP", rb_cObject);
413
+ rb_define_singleton_method(mGeoIP_ISP, "new", rb_geoip_isp_new, -1);
414
+ rb_define_method( mGeoIP_ISP, "look_up", rb_geoip_isp_look_up, 1);
415
+
416
+ mGeoIP_NetSpeed = rb_define_class_under(mGeoIP, "NetSpeed", rb_cObject);
417
+ rb_define_singleton_method(mGeoIP_NetSpeed, "new", rb_geoip_netspeed_new, -1);
418
+ rb_define_method( mGeoIP_NetSpeed, "look_up", rb_geoip_netspeed_look_up, 1);
419
+
420
+ mGeoIP_Domain = rb_define_class_under(mGeoIP, "Domain", rb_cObject);
421
+ rb_define_singleton_method(mGeoIP_Domain, "new", rb_geoip_domain_new, -1);
422
+ rb_define_method( mGeoIP_Domain, "look_up", rb_geoip_domain_look_up, 1);
423
+
424
+ rb_define_singleton_method(mGeoIP, "addr_to_num", rb_geoip_addr_to_num, 1);
425
+ rb_define_singleton_method(mGeoIP, "num_to_addr", rb_geoip_num_to_addr, 1);
426
+ }
data/test.rb ADDED
@@ -0,0 +1,226 @@
1
+ #encoding:UTF-8
2
+
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/geoip'
5
+ require 'rubygems'
6
+ # require 'ruby-debug'
7
+ # Debugger.start
8
+
9
+ CITY_DB = ENV.fetch("CITY", '/usr/local/share/GeoIP/GeoLiteCity.dat')
10
+ ORG_DB = ENV.fetch("ORG", '/usr/local/share/GeoIP/GeoIPOrg.dat')
11
+ REG_DB = ENV.fetch("REG", '/usr/local/share/GeoIP/GeoIPRegion.dat')
12
+
13
+ class Test::Unit::TestCase
14
+
15
+ def assert_look_up(db, addr, field, value)
16
+ h = db.look_up(addr)
17
+ assert_equal value, h[field]
18
+ h
19
+ end
20
+
21
+ end
22
+
23
+ class GeoIPTest < Test::Unit::TestCase
24
+
25
+ def setup
26
+ @ip = "24.24.24.24"
27
+ @ipnum = 16777216*24 + 65536*24 + 256*24 + 24
28
+
29
+ @large_ip = "245.245.245.245"
30
+ @large_ipnum = 16777216*245 + 65536*245 + 256*245 + 245
31
+ end
32
+
33
+ # addr_to_num
34
+
35
+ def test_addr_to_num_converts_an_ip_to_an_ipnum
36
+ assert_equal @ipnum, GeoIP.addr_to_num(@ip)
37
+ end
38
+
39
+ def test_addr_to_num_converts_large_ips_to_an_ipnum_correctly
40
+ assert_equal @large_ipnum, GeoIP.addr_to_num(@large_ip)
41
+ end
42
+
43
+ def test_addr_to_num_expects_an_ip_string
44
+ assert_raises TypeError do
45
+ GeoIP.addr_to_num(nil)
46
+ end
47
+ end
48
+
49
+ def test_addr_to_num_returns_zero_for_an_illformed_ip_string
50
+ assert_equal 0, GeoIP.addr_to_num("foo.bar")
51
+ end
52
+
53
+ # num_to_addr
54
+
55
+ def test_num_to_addr_converts_an_ipnum_to_an_ip
56
+ assert_equal @ip, GeoIP.num_to_addr(@ipnum)
57
+ end
58
+
59
+ def test_num_to_addr_converts_large_ipnums_to_an_ip_correctly
60
+ assert_equal @large_ip, GeoIP.num_to_addr(@large_ipnum)
61
+ end
62
+
63
+ def test_num_to_addr_expects_a_numeric_ip
64
+ assert_raises TypeError do
65
+ GeoIP.num_to_addr(nil)
66
+ end
67
+ assert_raises TypeError do
68
+ GeoIP.num_to_addr("foo.bar")
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ class GeoIPCityTest < Test::Unit::TestCase
75
+
76
+ def setup
77
+ ## Change me!
78
+ @dbfile = CITY_DB
79
+ end
80
+
81
+ def test_construction_default
82
+ db = GeoIP::City.new(@dbfile)
83
+
84
+ assert_raises TypeError do
85
+ db.look_up(nil)
86
+ end
87
+
88
+ h = db.look_up('24.24.24.24')
89
+ #debugger
90
+ assert_kind_of Hash, h
91
+ assert_equal 'New York', h[:city]
92
+ assert_equal 'United States', h[:country_name]
93
+ end
94
+
95
+ def test_construction_index
96
+ db = GeoIP::City.new(@dbfile, :index)
97
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
98
+ end
99
+
100
+ def test_construction_filesystem
101
+ db = GeoIP::City.new(@dbfile, :filesystem)
102
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
103
+ end
104
+
105
+ def test_construction_memory
106
+ db = GeoIP::City.new(@dbfile, :memory)
107
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
108
+ end
109
+
110
+ def test_construction_filesystem_check
111
+ db = GeoIP::City.new(@dbfile, :filesystem, true)
112
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
113
+ end
114
+
115
+ def test_bad_db_file
116
+ assert_raises Errno::ENOENT do
117
+ GeoIP::City.new('/supposed-to-fail')
118
+ end
119
+ end
120
+
121
+ def test_character_encoding_converted_to_utf8_first
122
+ db = GeoIP::City.new(@dbfile, :filesystem, true)
123
+ assert_look_up(db, '201.85.50.148', :city, 'São Paulo')
124
+ end
125
+
126
+ end
127
+
128
+ class GeoIPOrgTest < Test::Unit::TestCase
129
+
130
+ def setup
131
+ ## Change me!
132
+ @dbfile = ORG_DB
133
+ end
134
+
135
+ def test_construction_default
136
+ db = GeoIP::Organization.new(@dbfile)
137
+
138
+ assert_raises TypeError do
139
+ db.look_up(nil)
140
+ end
141
+
142
+ h = db.look_up('24.24.24.24')
143
+ assert_kind_of Hash, h
144
+ assert_equal 'Road Runner', h[:name]
145
+ end
146
+
147
+ def test_construction_index
148
+ db = GeoIP::Organization.new(@dbfile, :index)
149
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
150
+ end
151
+
152
+ def test_construction_filesystem
153
+ db = GeoIP::Organization.new(@dbfile, :filesystem)
154
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
155
+ end
156
+
157
+ def test_construction_memory
158
+ db = GeoIP::Organization.new(@dbfile, :memory)
159
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
160
+ end
161
+
162
+ def test_construction_filesystem_check
163
+ db = GeoIP::Organization.new(@dbfile, :filesystem, true)
164
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
165
+ end
166
+
167
+ def test_bad_db_file
168
+ assert_raises Errno::ENOENT do
169
+ GeoIP::Organization.new('/supposed-to-fail')
170
+ end
171
+ end
172
+
173
+ end
174
+
175
+
176
+
177
+ class GeoIPRegionTest < Test::Unit::TestCase
178
+
179
+ def setup
180
+ ## Change me!
181
+ @dbfile = REG_DB
182
+ end
183
+
184
+ def test_construction_default
185
+ db = GeoIP::Region.new(@dbfile)
186
+
187
+ assert_raises TypeError do
188
+ db.look_up(nil)
189
+ end
190
+
191
+ h = db.look_up('24.24.24.24')
192
+ #debugger
193
+ assert_kind_of Hash, h
194
+ assert_equal 'NY', h[:region]
195
+ assert_equal 'US', h[:country_code]
196
+ assert_equal 'United States', h[:country_name]
197
+ end
198
+
199
+ def test_construction_memory
200
+ db = GeoIP::Region.new(@dbfile, :memory)
201
+ assert_look_up(db, '24.24.24.24', :region, 'NY')
202
+ end
203
+
204
+ def test_construction_index
205
+ db = GeoIP::Region.new(@dbfile, :index)
206
+ assert_look_up(db, '24.24.24.24', :region, 'NY')
207
+ end
208
+
209
+ def test_construction_filesystem
210
+ db = GeoIP::Region.new(@dbfile, :filesystem)
211
+ assert_look_up(db, '24.24.24.24', :region, 'NY')
212
+ end
213
+
214
+ def test_construction_filesystem_check
215
+ db = GeoIP::Region.new(@dbfile, :filesystem, true)
216
+ assert_look_up(db, '24.24.24.24', :region, 'NY')
217
+ end
218
+
219
+ def test_bad_db_file
220
+ assert_raises Errno::ENOENT do
221
+ GeoIP::Region.new('/supposed-to-fail')
222
+ end
223
+ end
224
+
225
+
226
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sumdog-geoip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryah Dahl
9
+ - Matt Todd
10
+ - Mat Byczkowski
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2011-08-16 00:00:00.000000000 +01:00
15
+ default_executable:
16
+ dependencies: []
17
+ description: Generic GeoIP lookup tool. Based on the geoip-c RubyGem by Matt Todd
18
+ email: mbyczkowski@gmail.com
19
+ executables: []
20
+ extensions:
21
+ - extconf.rb
22
+ extra_rdoc_files: []
23
+ files:
24
+ - Rakefile
25
+ - extconf.rb
26
+ - test.rb
27
+ - geoip.c
28
+ - README.md
29
+ has_rdoc: true
30
+ homepage: http://github.com/mtodd/geoip
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - .
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.6.2
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: A Binding to the GeoIP C library
54
+ test_files:
55
+ - test.rb