geoip-c-ct 0.7.1a

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 +414 -0
  5. data/test.rb +170 -0
  6. metadata +55 -0
@@ -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.
@@ -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 = 'geoip-c'
25
+ s.version = "0.7.2"
26
+
27
+ s.authors = ['Ryah Dahl', 'Matt Todd']
28
+ s.email = 'mtodd@highgroove.com'
29
+
30
+ s.summary = "A Binding to the GeoIP C library"
31
+ s.description = 'Generic GeoIP lookup tool. Based on the geoip_city RubyGem by Ryah Dahl'
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/geoip-c-0.5.0.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
@@ -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,414 @@
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_Country6;
17
+ static VALUE mGeoIP_Organization;
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::Country6 ***********************************************************/
209
+
210
+ /* GeoIP::Country6.new('/path/to/GeoIPCountry.dat')
211
+ * load_option is not required for this database because it is ignored.
212
+ */
213
+ static VALUE rb_geoip_country6_new(int argc, VALUE *argv, VALUE self)
214
+ {
215
+ return rb_geoip_database_new(mGeoIP_Country6, argc, argv, self);
216
+ }
217
+
218
+ /* Pass this function an IP address as a string, it will return a hash
219
+ * containing all the information that the database knows about the IP
220
+ * db.look_up('2001:0db8:85a3:0000:0000:8a2e:0370:7334')
221
+ * => {:country_code=>"US",
222
+ * :country_code3=>"USA",
223
+ * :country_name=>"United States"}
224
+ */
225
+ VALUE rb_geoip_country6_look_up(VALUE self, VALUE addr) {
226
+ GeoIP *gi;
227
+ VALUE hash = Qnil;
228
+ int country_id;
229
+
230
+ Check_Type(addr, T_STRING);
231
+ Data_Get_Struct(self, GeoIP, gi);
232
+ country_id = GeoIP_id_by_addr_v6(gi, StringValuePtr(addr));
233
+ if(country_id < 1) return Qnil;
234
+
235
+ hash = rb_hash_new();
236
+ rb_hash_sset(hash, "country_code", rb_str_new2(GeoIP_country_code[country_id]));
237
+ rb_hash_sset(hash, "country_code3", rb_str_new2(GeoIP_country_code3[country_id]));
238
+ rb_hash_sset(hash, "country_name", rb_str_new2(GeoIP_country_name[country_id]));
239
+
240
+ return hash;
241
+ }
242
+
243
+ /* GeoIP::Organization *******************************************************/
244
+
245
+ /* GeoIP::Organization.new('/path/to/GeoIPOrg.dat', load_option)
246
+ * load_option can be:
247
+ * * :memory - load the data into memory, fastest (default)
248
+ * * :filesystem - look up from filesystem, least memory intensive
249
+ * * :index - stores in memory most recent queries
250
+ *
251
+ */
252
+ static VALUE rb_geoip_org_new(int argc, VALUE *argv, VALUE self)
253
+ {
254
+ return rb_geoip_database_new(mGeoIP_Organization, argc, argv, self);
255
+ }
256
+
257
+ /* Pass this function an IP address as a string, it will return a hash
258
+ * containing all the information that the database knows about the IP:
259
+ * db.look_up('24.24.24.24')
260
+ * => {:name => "Road Runner"}
261
+ */
262
+ VALUE rb_geoip_org_look_up(VALUE self, VALUE addr) {
263
+ GeoIP *gi;
264
+ Check_Type(addr, T_STRING);
265
+ Data_Get_Struct(self, GeoIP, gi);
266
+ return generic_single_value_lookup_response("name", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
267
+ }
268
+
269
+ /* GeoIP::ISP *******************************************************/
270
+
271
+ /* GeoIP::ISP.new('/path/to/GeoIPISP.dat', load_option)
272
+ * load_option can be:
273
+ * * :memory - load the data into memory, fastest (default)
274
+ * * :filesystem - look up from filesystem, least memory intensive
275
+ * * :index - stores in memory most recent queries
276
+ *
277
+ */
278
+ static VALUE rb_geoip_isp_new(int argc, VALUE *argv, VALUE self)
279
+ {
280
+ return rb_geoip_database_new(mGeoIP_ISP, argc, argv, self);
281
+ }
282
+
283
+ /* Pass this function an IP address as a string, it will return a hash
284
+ * containing all the information that the database knows about the IP:
285
+ * db.look_up('24.24.24.24')
286
+ * => {:isp => "Road Runner"}
287
+ */
288
+ VALUE rb_geoip_isp_look_up(VALUE self, VALUE addr) {
289
+ GeoIP *gi;
290
+ Check_Type(addr, T_STRING);
291
+ Data_Get_Struct(self, GeoIP, gi);
292
+ return generic_single_value_lookup_response("isp", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
293
+ }
294
+
295
+ /* GeoIP::NetSpeed *******************************************************/
296
+
297
+ /* GeoIP::NetSpeed.new('/path/to/GeoIPNetSpeed.dat', load_option)
298
+ * load_option can be:
299
+ * * :memory - load the data into memory, fastest (default)
300
+ * * :filesystem - look up from filesystem, least memory intensive
301
+ * * :index - stores in memory most recent queries
302
+ *
303
+ */
304
+ static VALUE rb_geoip_netspeed_new(int argc, VALUE *argv, VALUE self)
305
+ {
306
+ return rb_geoip_database_new(mGeoIP_NetSpeed, argc, argv, self);
307
+ }
308
+
309
+ /* Pass this function an IP address as a string, it will return a hash
310
+ * containing all the information that the database knows about the IP:
311
+ * db.look_up('24.24.24.24')
312
+ * => {:netspeed => "Cable/DSL"}
313
+ */
314
+ VALUE rb_geoip_netspeed_look_up(VALUE self, VALUE addr) {
315
+ GeoIP *gi;
316
+ Check_Type(addr, T_STRING);
317
+ Data_Get_Struct(self, GeoIP, gi);
318
+ return generic_single_value_lookup_response("netspeed", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
319
+ }
320
+
321
+ /* GeoIP::Domain *******************************************************/
322
+
323
+ /* GeoIP::Domain.new('/path/to/GeoIPDomain.dat', load_option)
324
+ * load_option can be:
325
+ * * :memory - load the data into memory, fastest (default)
326
+ * * :filesystem - look up from filesystem, least memory intensive
327
+ * * :index - stores in memory most recent queries
328
+ *
329
+ */
330
+ static VALUE rb_geoip_domain_new(int argc, VALUE *argv, VALUE self)
331
+ {
332
+ return rb_geoip_database_new(mGeoIP_Domain, argc, argv, self);
333
+ }
334
+
335
+ /* Pass this function an IP address as a string, it will return a hash
336
+ * containing all the information that the database knows about the IP:
337
+ * db.look_up('24.24.24.24')
338
+ * => {:domain => "rr.com"}
339
+ */
340
+ VALUE rb_geoip_domain_look_up(VALUE self, VALUE addr) {
341
+ GeoIP *gi;
342
+ Check_Type(addr, T_STRING);
343
+ Data_Get_Struct(self, GeoIP, gi);
344
+ return generic_single_value_lookup_response("domain", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
345
+ }
346
+
347
+ /* GeoIP *********************************************************************/
348
+
349
+ /* Returns the numeric form of an IP address.
350
+ *
351
+ * For example:
352
+ * 24.24.24.24 => 404232216
353
+ *
354
+ * This is used in order to be able to perform searches in CSV versions of the
355
+ * data files or in SQL records if the data has been put there.
356
+ */
357
+ VALUE rb_geoip_addr_to_num(VALUE self, VALUE addr) {
358
+ Check_Type(addr, T_STRING);
359
+ return UINT2NUM((unsigned int)_GeoIP_addr_to_num(StringValuePtr(addr)));
360
+ }
361
+
362
+ // Fixes a bug with 64bit architectures where this delcaration doesn't exist
363
+ // in the GeoIP library causing segmentation faults.
364
+ char *_GeoIP_num_to_addr(GeoIP* gi, unsigned long ipnum);
365
+
366
+ VALUE rb_geoip_num_to_addr(VALUE self, VALUE num) {
367
+ VALUE num_type = TYPE(num);
368
+ switch(num_type) {
369
+ case T_FIXNUM: break;
370
+ case T_BIGNUM: break;
371
+ default: rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Bignum)", rb_obj_classname(num));
372
+ }
373
+ return rb_str_new2((char*)_GeoIP_num_to_addr(NULL, (unsigned long)NUM2ULONG(num)));
374
+ }
375
+
376
+ void Init_geoip()
377
+ {
378
+ mGeoIP = rb_define_module("GeoIP");
379
+
380
+ rb_geoip_memory = ID2SYM(rb_intern("memory"));
381
+ rb_geoip_filesystem = ID2SYM(rb_intern("filesystem"));
382
+ rb_geoip_index = ID2SYM(rb_intern("index"));
383
+
384
+ mGeoIP_City = rb_define_class_under(mGeoIP, "City", rb_cObject);
385
+ rb_define_singleton_method(mGeoIP_City, "new", rb_geoip_city_new, -1);
386
+ rb_define_method( mGeoIP_City, "look_up", rb_geoip_city_look_up, 1);
387
+
388
+ mGeoIP_Country = rb_define_class_under(mGeoIP, "Country", rb_cObject);
389
+ rb_define_singleton_method(mGeoIP_Country, "new", rb_geoip_country_new, -1);
390
+ rb_define_method( mGeoIP_Country, "look_up", rb_geoip_country_look_up, 1);
391
+
392
+ mGeoIP_Country6 = rb_define_class_under(mGeoIP, "Country6", rb_cObject);
393
+ rb_define_singleton_method(mGeoIP_Country6, "new", rb_geoip_country6_new, -1);
394
+ rb_define_method( mGeoIP_Country6, "look_up", rb_geoip_country6_look_up, 1);
395
+
396
+ mGeoIP_Organization = rb_define_class_under(mGeoIP, "Organization", rb_cObject);
397
+ rb_define_singleton_method(mGeoIP_Organization, "new", rb_geoip_org_new, -1);
398
+ rb_define_method( mGeoIP_Organization, "look_up", rb_geoip_org_look_up, 1);
399
+
400
+ mGeoIP_ISP = rb_define_class_under(mGeoIP, "ISP", rb_cObject);
401
+ rb_define_singleton_method(mGeoIP_ISP, "new", rb_geoip_isp_new, -1);
402
+ rb_define_method( mGeoIP_ISP, "look_up", rb_geoip_isp_look_up, 1);
403
+
404
+ mGeoIP_NetSpeed = rb_define_class_under(mGeoIP, "NetSpeed", rb_cObject);
405
+ rb_define_singleton_method(mGeoIP_NetSpeed, "new", rb_geoip_netspeed_new, -1);
406
+ rb_define_method( mGeoIP_NetSpeed, "look_up", rb_geoip_netspeed_look_up, 1);
407
+
408
+ mGeoIP_Domain = rb_define_class_under(mGeoIP, "Domain", rb_cObject);
409
+ rb_define_singleton_method(mGeoIP_Domain, "new", rb_geoip_domain_new, -1);
410
+ rb_define_method( mGeoIP_Domain, "look_up", rb_geoip_domain_look_up, 1);
411
+
412
+ rb_define_singleton_method(mGeoIP, "addr_to_num", rb_geoip_addr_to_num, 1);
413
+ rb_define_singleton_method(mGeoIP, "num_to_addr", rb_geoip_num_to_addr, 1);
414
+ }
data/test.rb ADDED
@@ -0,0 +1,170 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/geoip'
3
+ require 'rubygems'
4
+ # require 'ruby-debug'
5
+ # Debugger.start
6
+
7
+ CITY_DB = ENV.fetch("CITY", '/usr/local/GeoIP/share/GeoIP/GeoLiteCity.dat')
8
+ ORG_DB = ENV.fetch("ORG", '/usr/local/GeoIP/share/GeoIP/GeoIPOrg.dat')
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ def assert_look_up(db, addr, field, value)
13
+ h = db.look_up(addr)
14
+ assert_equal value, h[field]
15
+ h
16
+ end
17
+
18
+ end
19
+
20
+ class GeoIPTest < Test::Unit::TestCase
21
+
22
+ def setup
23
+ @ip = "24.24.24.24"
24
+ @ipnum = 16777216*24 + 65536*24 + 256*24 + 24
25
+
26
+ @large_ip = "245.245.245.245"
27
+ @large_ipnum = 16777216*245 + 65536*245 + 256*245 + 245
28
+ end
29
+
30
+ # addr_to_num
31
+
32
+ def test_addr_to_num_converts_an_ip_to_an_ipnum
33
+ assert_equal @ipnum, GeoIP.addr_to_num(@ip)
34
+ end
35
+
36
+ def test_addr_to_num_converts_large_ips_to_an_ipnum_correctly
37
+ assert_equal @large_ipnum, GeoIP.addr_to_num(@large_ip)
38
+ end
39
+
40
+ def test_addr_to_num_expects_an_ip_string
41
+ assert_raises TypeError do
42
+ GeoIP.addr_to_num(nil)
43
+ end
44
+ end
45
+
46
+ def test_addr_to_num_returns_zero_for_an_illformed_ip_string
47
+ assert_equal 0, GeoIP.addr_to_num("foo.bar")
48
+ end
49
+
50
+ # num_to_addr
51
+
52
+ def test_num_to_addr_converts_an_ipnum_to_an_ip
53
+ assert_equal @ip, GeoIP.num_to_addr(@ipnum)
54
+ end
55
+
56
+ def test_num_to_addr_converts_large_ipnums_to_an_ip_correctly
57
+ assert_equal @large_ip, GeoIP.num_to_addr(@large_ipnum)
58
+ end
59
+
60
+ def test_num_to_addr_expects_a_numeric_ip
61
+ assert_raises TypeError do
62
+ GeoIP.num_to_addr(nil)
63
+ end
64
+ assert_raises TypeError do
65
+ GeoIP.num_to_addr("foo.bar")
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ class GeoIPCityTest < Test::Unit::TestCase
72
+
73
+ def setup
74
+ ## Change me!
75
+ @dbfile = CITY_DB
76
+ end
77
+
78
+ def test_construction_default
79
+ db = GeoIP::City.new(@dbfile)
80
+
81
+ assert_raises TypeError do
82
+ db.look_up(nil)
83
+ end
84
+
85
+ h = db.look_up('24.24.24.24')
86
+ #debugger
87
+ assert_kind_of Hash, h
88
+ assert_equal 'New York', h[:city]
89
+ assert_equal 'United States', h[:country_name]
90
+ end
91
+
92
+ def test_construction_index
93
+ db = GeoIP::City.new(@dbfile, :index)
94
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
95
+ end
96
+
97
+ def test_construction_filesystem
98
+ db = GeoIP::City.new(@dbfile, :filesystem)
99
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
100
+ end
101
+
102
+ def test_construction_memory
103
+ db = GeoIP::City.new(@dbfile, :memory)
104
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
105
+ end
106
+
107
+ def test_construction_filesystem_check
108
+ db = GeoIP::City.new(@dbfile, :filesystem, true)
109
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
110
+ end
111
+
112
+ def test_bad_db_file
113
+ assert_raises Errno::ENOENT do
114
+ GeoIP::City.new('/supposed-to-fail')
115
+ end
116
+ end
117
+
118
+ def test_character_encoding_converted_to_utf8_first
119
+ db = GeoIP::City.new(@dbfile, :filesystem, true)
120
+ assert_look_up(db, '201.85.50.148', :city, 'São Paulo')
121
+ end
122
+
123
+ end
124
+
125
+ class GeoIPOrgTest < Test::Unit::TestCase
126
+
127
+ def setup
128
+ ## Change me!
129
+ @dbfile = ORG_DB
130
+ end
131
+
132
+ def test_construction_default
133
+ db = GeoIP::Organization.new(@dbfile)
134
+
135
+ assert_raises TypeError do
136
+ db.look_up(nil)
137
+ end
138
+
139
+ h = db.look_up('24.24.24.24')
140
+ assert_kind_of Hash, h
141
+ assert_equal 'Road Runner', h[:name]
142
+ end
143
+
144
+ def test_construction_index
145
+ db = GeoIP::Organization.new(@dbfile, :index)
146
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
147
+ end
148
+
149
+ def test_construction_filesystem
150
+ db = GeoIP::Organization.new(@dbfile, :filesystem)
151
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
152
+ end
153
+
154
+ def test_construction_memory
155
+ db = GeoIP::Organization.new(@dbfile, :memory)
156
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
157
+ end
158
+
159
+ def test_construction_filesystem_check
160
+ db = GeoIP::Organization.new(@dbfile, :filesystem, true)
161
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
162
+ end
163
+
164
+ def test_bad_db_file
165
+ assert_raises Errno::ENOENT do
166
+ GeoIP::Organization.new('/supposed-to-fail')
167
+ end
168
+ end
169
+
170
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geoip-c-ct
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.1a
5
+ prerelease: 5
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Dahl
9
+ - Matt Todd
10
+ - Charles Brian Quinn
11
+ - Michael Sheakoski
12
+ - Silvio Quadri
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+ date: 2012-03-09 00:00:00.000000000 Z
17
+ dependencies: []
18
+ description: Generic GeoIP lookup tool. Based on the geoip_city RubyGem by Ryan Dahl
19
+ email: mtodd@highgroove.com
20
+ executables: []
21
+ extensions:
22
+ - extconf.rb
23
+ extra_rdoc_files: []
24
+ files:
25
+ - Rakefile
26
+ - extconf.rb
27
+ - test.rb
28
+ - geoip.c
29
+ - README.md
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: 1.3.1
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 1.8.11
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: A Binding to the GeoIP C library
54
+ test_files:
55
+ - test.rb