bitium-geoip-c 0.8.1

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 (7) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +160 -0
  3. data/Rakefile +55 -0
  4. data/extconf.rb +19 -0
  5. data/geoip.c +408 -0
  6. data/test.rb +175 -0
  7. metadata +57 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2852d7ce55698d783c1f10d714dd2e37cf8780ab
4
+ data.tar.gz: 3d75afaf70a65129fcc1e9a1079f25255d12a589
5
+ SHA512:
6
+ metadata.gz: f922e7d7785f57a25e1ddc3b89ea2f56f8667d3e8db5d771acd05676f44eb2de02879e4e00a763f0e4349af7bd5316dfd125ad12520efe86396f6fd9e76c3bd8
7
+ data.tar.gz: 7256508bb9da37cbfdbc18f631c4e90165deb8a395a6a4b40fc9bdad312210f86de264955caa1c1c13c52103162c29dc7c1209653100a915df10520c41090ee2
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
+ /usr/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 = 'geoip-c'
25
+ s.version = "0.8.1"
26
+
27
+ s.authors = ['Ryah Dahl', 'Matt Todd', 'Andy Lindeman']
28
+ s.email = ['alindeman@gmail.com', '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
data/extconf.rb ADDED
@@ -0,0 +1,19 @@
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
+ # Defines HAVE_GEOIP_ADDR_TO_NUM
11
+ have_func('GeoIP_addr_to_num', 'GeoIP.h')
12
+
13
+ # Defines HAVE_GEOIP_NUM_TO_ADDR
14
+ have_func('GeoIP_num_to_addr', 'GeoIP.h')
15
+
16
+ create_makefile('geoip')
17
+ else
18
+ abort("you must have geoip c library installed!")
19
+ end
data/geoip.c ADDED
@@ -0,0 +1,408 @@
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_ISP;
18
+ static VALUE mGeoIP_NetSpeed;
19
+ static VALUE mGeoIP_Domain;
20
+ static VALUE mGeoIP_TimeZone;
21
+ static VALUE rb_geoip_memory;
22
+ static VALUE rb_geoip_filesystem;
23
+ static VALUE rb_geoip_index;
24
+
25
+ #ifndef HAVE_GEOIP_ADDR_TO_NUM
26
+ // Support geoip <= 1.4.6
27
+ #define GeoIP_addr_to_num _GeoIP_addr_to_num
28
+ #endif
29
+
30
+ #ifndef HAVE_GEOIP_NUM_TO_ADDR
31
+ // Support geoip <= 1.4.6
32
+
33
+ // Fixes a bug with 64bit architectures where this delcaration doesn't exist
34
+ // in the GeoIP library causing segmentation faults.
35
+ char *_GeoIP_num_to_addr(GeoIP* gi, unsigned long ipnum);
36
+ #define GeoIP_num_to_addr(ipnum) _GeoIP_num_to_addr(NULL, ipnum)
37
+ #endif
38
+
39
+ /* helpers */
40
+ void rb_hash_sset(VALUE hash, const char *str, VALUE v) {
41
+ rb_hash_aset(hash, ID2SYM(rb_intern(str)), v);
42
+ }
43
+
44
+ /* pulled from http://blog.inventic.eu/?p=238 and
45
+ https://github.com/Vagabond/erlang-iconv/blob/master/c_src/iconv_drv.c */
46
+ static VALUE encode_to_utf8_and_return_rb_str(char *value) {
47
+ char dst[BUFSIZ];
48
+ if (value==NULL) {
49
+ return rb_str_new2("");
50
+ }
51
+ size_t srclen = strlen(value);
52
+ size_t dstlen = srclen * 2;
53
+
54
+ char * pIn = value;
55
+ char * pOut = ( char*)dst;
56
+
57
+ iconv_t cd = iconv_open("UTF-8","ISO-8859-1");
58
+ iconv(cd, &pIn, &srclen, &pOut, &dstlen);
59
+ iconv_close(cd);
60
+
61
+ *(pOut++) = 0; /* ensure we null terminate */
62
+
63
+ return rb_str_new2(dst);
64
+ }
65
+
66
+ int check_load_option(VALUE load_option) {
67
+ if(load_option == rb_geoip_memory) {
68
+ return GEOIP_MEMORY_CACHE;
69
+ } else if(load_option == rb_geoip_filesystem) {
70
+ return GEOIP_STANDARD;
71
+ } else if(load_option == rb_geoip_index) {
72
+ return GEOIP_INDEX_CACHE;
73
+ } else {
74
+ rb_raise(rb_eTypeError, "the second option must be :memory, :filesystem, or :index");
75
+ return Qnil;
76
+ }
77
+ }
78
+
79
+ /* Generic initializer */
80
+ static VALUE rb_geoip_database_new(VALUE mGeoIP_Database_Class, int argc, VALUE *argv, VALUE self)
81
+ {
82
+ GeoIP *gi;
83
+ VALUE database = Qnil;
84
+ VALUE filename, load_option = Qnil, check_cache = Qnil;
85
+ int flag;
86
+
87
+ rb_scan_args(argc, argv, "12", &filename, &load_option, &check_cache);
88
+ if(NIL_P(load_option))
89
+ load_option = rb_geoip_memory;
90
+ if(NIL_P(check_cache))
91
+ check_cache = Qfalse;
92
+ Check_Type(load_option, T_SYMBOL);
93
+
94
+ if(flag = check_load_option(load_option)) flag;
95
+
96
+ if(RTEST(check_cache)) flag |= GEOIP_CHECK_CACHE;
97
+
98
+ if(gi = GeoIP_open(StringValuePtr(filename), flag)) {
99
+ database = Data_Wrap_Struct(mGeoIP_Database_Class, 0, GeoIP_delete, gi);
100
+ rb_obj_call_init(database, 0, 0);
101
+ } else {
102
+ rb_sys_fail("Problem opening database");
103
+ }
104
+ return database;
105
+ }
106
+
107
+ /* Generic, single-value look up method */
108
+ static VALUE generic_single_value_lookup_response(char *key, char *value)
109
+ {
110
+ VALUE result = rb_hash_new();
111
+ if(value) {
112
+ rb_hash_sset(result, key, encode_to_utf8_and_return_rb_str(value));
113
+ return result;
114
+ } else {
115
+ return Qnil;
116
+ }
117
+ }
118
+
119
+ /* GeoIP::City ***************************************************************/
120
+
121
+ VALUE rb_city_record_to_hash(GeoIPRecord *record)
122
+ {
123
+ VALUE hash = rb_hash_new();
124
+
125
+ if(record->country_code)
126
+ rb_hash_sset(hash, "country_code", encode_to_utf8_and_return_rb_str(record->country_code));
127
+ if(record->country_code3)
128
+ rb_hash_sset(hash, "country_code3", encode_to_utf8_and_return_rb_str(record->country_code3));
129
+ if(record->country_name)
130
+ rb_hash_sset(hash, "country_name", encode_to_utf8_and_return_rb_str(record->country_name));
131
+ if(record->region) {
132
+ rb_hash_sset(hash, "region", encode_to_utf8_and_return_rb_str(record->region));
133
+ rb_hash_sset(hash, "region_name", encode_to_utf8_and_return_rb_str(GeoIP_region_name_by_code(record->country_code, record->region)));
134
+ }
135
+ if(record->city)
136
+ rb_hash_sset(hash, "city", encode_to_utf8_and_return_rb_str(record->city));
137
+ if(record->postal_code)
138
+ rb_hash_sset(hash, "postal_code", encode_to_utf8_and_return_rb_str(record->postal_code));
139
+ if(record->latitude)
140
+ rb_hash_sset(hash, "latitude", rb_float_new((double)record->latitude));
141
+ if(record->longitude)
142
+ rb_hash_sset(hash, "longitude", rb_float_new((double)record->longitude));
143
+ if(record->dma_code)
144
+ rb_hash_sset(hash, "dma_code", INT2NUM(record->dma_code));
145
+ if(record->area_code)
146
+ rb_hash_sset(hash, "area_code", INT2NUM(record->area_code));
147
+
148
+ return hash;
149
+ }
150
+
151
+ /* The first argument is the filename of the GeoIPCity.dat file
152
+ * load_option = :standard, :index, or :memory. default :memory
153
+ * check_cache = true or false. default false
154
+ *
155
+ * filesystem: read database from filesystem, uses least memory.
156
+ *
157
+ * index: the most frequently accessed index portion of the database,
158
+ * resulting in faster lookups than :filesystem, but less memory usage than
159
+ * :memory.
160
+ *
161
+ * memory: load database into memory, faster performance but uses more
162
+ * memory.
163
+ */
164
+ static VALUE rb_geoip_city_new(int argc, VALUE *argv, VALUE self)
165
+ {
166
+ return rb_geoip_database_new(mGeoIP_City, argc, argv, self);
167
+ }
168
+
169
+ /* Pass this function an IP address as a string, it will return a hash
170
+ * containing all the information that the database knows about the IP
171
+ * db.look_up('24.24.24.24')
172
+ * => {:city=>"Ithaca", :latitude=>42.4277992248535,
173
+ * :country_code=>"US", :longitude=>-76.4981994628906,
174
+ * :country_code3=>"USA", :dma_code=>555,
175
+ * :country_name=>"United States", :area_code=>607,
176
+ * :region=>"NY"}
177
+ */
178
+ VALUE rb_geoip_city_look_up(VALUE self, VALUE addr) {
179
+ GeoIP *gi;
180
+ GeoIPRecord *record = NULL;
181
+ VALUE hash = Qnil;
182
+
183
+ Check_Type(addr, T_STRING);
184
+ Data_Get_Struct(self, GeoIP, gi);
185
+ if(record = GeoIP_record_by_addr(gi, StringValuePtr(addr))) {
186
+ hash = rb_city_record_to_hash(record);
187
+ GeoIPRecord_delete(record);
188
+ }
189
+ return hash;
190
+ }
191
+
192
+ /* GeoIP::Country ************************************************************/
193
+
194
+ /* GeoIP::Country.new('/path/to/GeoIPCountry.dat')
195
+ * load_option is not required for this database because it is ignored.
196
+ */
197
+ static VALUE rb_geoip_country_new(int argc, VALUE *argv, VALUE self)
198
+ {
199
+ return rb_geoip_database_new(mGeoIP_Country, argc, argv, self);
200
+ }
201
+
202
+ /* Pass this function an IP address as a string, it will return a hash
203
+ * containing all the information that the database knows about the IP
204
+ * db.look_up('24.24.24.24')
205
+ * => {:country_code=>"US",
206
+ * :country_code3=>"USA",
207
+ * :country_name=>"United States"}
208
+ */
209
+ VALUE rb_geoip_country_look_up(VALUE self, VALUE addr) {
210
+ GeoIP *gi;
211
+ VALUE hash = Qnil;
212
+ int country_id;
213
+
214
+ Check_Type(addr, T_STRING);
215
+ Data_Get_Struct(self, GeoIP, gi);
216
+ country_id = GeoIP_id_by_addr(gi, StringValuePtr(addr));
217
+ if(country_id < 1) return Qnil;
218
+
219
+ hash = rb_hash_new();
220
+ rb_hash_sset(hash, "country_code", rb_str_new2(GeoIP_country_code[country_id]));
221
+ rb_hash_sset(hash, "country_code3", rb_str_new2(GeoIP_country_code3[country_id]));
222
+ rb_hash_sset(hash, "country_name", rb_str_new2(GeoIP_country_name[country_id]));
223
+
224
+ return hash;
225
+ }
226
+
227
+ /* GeoIP::Organization *******************************************************/
228
+
229
+ /* GeoIP::Organization.new('/path/to/GeoIPOrg.dat', load_option)
230
+ * load_option can be:
231
+ * * :memory - load the data into memory, fastest (default)
232
+ * * :filesystem - look up from filesystem, least memory intensive
233
+ * * :index - stores in memory most recent queries
234
+ *
235
+ */
236
+ static VALUE rb_geoip_org_new(int argc, VALUE *argv, VALUE self)
237
+ {
238
+ return rb_geoip_database_new(mGeoIP_Organization, argc, argv, self);
239
+ }
240
+
241
+ /* Pass this function an IP address as a string, it will return a hash
242
+ * containing all the information that the database knows about the IP:
243
+ * db.look_up('24.24.24.24')
244
+ * => {:name => "Road Runner"}
245
+ */
246
+ VALUE rb_geoip_org_look_up(VALUE self, VALUE addr) {
247
+ GeoIP *gi;
248
+ Check_Type(addr, T_STRING);
249
+ Data_Get_Struct(self, GeoIP, gi);
250
+ return generic_single_value_lookup_response("name", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
251
+ }
252
+
253
+ /* GeoIP::ISP *******************************************************/
254
+
255
+ /* GeoIP::ISP.new('/path/to/GeoIPISP.dat', load_option)
256
+ * load_option can be:
257
+ * * :memory - load the data into memory, fastest (default)
258
+ * * :filesystem - look up from filesystem, least memory intensive
259
+ * * :index - stores in memory most recent queries
260
+ *
261
+ */
262
+ static VALUE rb_geoip_isp_new(int argc, VALUE *argv, VALUE self)
263
+ {
264
+ return rb_geoip_database_new(mGeoIP_ISP, argc, argv, self);
265
+ }
266
+
267
+ /* Pass this function an IP address as a string, it will return a hash
268
+ * containing all the information that the database knows about the IP:
269
+ * db.look_up('24.24.24.24')
270
+ * => {:isp => "Road Runner"}
271
+ */
272
+ VALUE rb_geoip_isp_look_up(VALUE self, VALUE addr) {
273
+ GeoIP *gi;
274
+ Check_Type(addr, T_STRING);
275
+ Data_Get_Struct(self, GeoIP, gi);
276
+ return generic_single_value_lookup_response("isp", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
277
+ }
278
+
279
+ /* GeoIP::NetSpeed *******************************************************/
280
+
281
+ /* GeoIP::NetSpeed.new('/path/to/GeoIPNetSpeed.dat', load_option)
282
+ * load_option can be:
283
+ * * :memory - load the data into memory, fastest (default)
284
+ * * :filesystem - look up from filesystem, least memory intensive
285
+ * * :index - stores in memory most recent queries
286
+ *
287
+ */
288
+ static VALUE rb_geoip_netspeed_new(int argc, VALUE *argv, VALUE self)
289
+ {
290
+ return rb_geoip_database_new(mGeoIP_NetSpeed, argc, argv, self);
291
+ }
292
+
293
+ /* Pass this function an IP address as a string, it will return a hash
294
+ * containing all the information that the database knows about the IP:
295
+ * db.look_up('24.24.24.24')
296
+ * => {:netspeed => "Cable/DSL"}
297
+ */
298
+ VALUE rb_geoip_netspeed_look_up(VALUE self, VALUE addr) {
299
+ GeoIP *gi;
300
+ Check_Type(addr, T_STRING);
301
+ Data_Get_Struct(self, GeoIP, gi);
302
+ return generic_single_value_lookup_response("netspeed", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
303
+ }
304
+
305
+ /* GeoIP::Domain *******************************************************/
306
+
307
+ /* GeoIP::Domain.new('/path/to/GeoIPDomain.dat', load_option)
308
+ * load_option can be:
309
+ * * :memory - load the data into memory, fastest (default)
310
+ * * :filesystem - look up from filesystem, least memory intensive
311
+ * * :index - stores in memory most recent queries
312
+ *
313
+ */
314
+ static VALUE rb_geoip_domain_new(int argc, VALUE *argv, VALUE self)
315
+ {
316
+ return rb_geoip_database_new(mGeoIP_Domain, argc, argv, self);
317
+ }
318
+
319
+ /* Pass this function an IP address as a string, it will return a hash
320
+ * containing all the information that the database knows about the IP:
321
+ * db.look_up('24.24.24.24')
322
+ * => {:domain => "rr.com"}
323
+ */
324
+ VALUE rb_geoip_domain_look_up(VALUE self, VALUE addr) {
325
+ GeoIP *gi;
326
+ Check_Type(addr, T_STRING);
327
+ Data_Get_Struct(self, GeoIP, gi);
328
+ return generic_single_value_lookup_response("domain", GeoIP_name_by_addr(gi, StringValuePtr(addr)));
329
+ }
330
+
331
+ /* GeoIP::TimeZone *******************************************************/
332
+
333
+ /* GeoIP::TimeZone.look_up(country, region)
334
+ */
335
+ static VALUE rb_geoip_timezone_lookup(VALUE self, VALUE country, VALUE region)
336
+ {
337
+ Check_Type(country, T_STRING);
338
+ Check_Type(region, T_STRING);
339
+
340
+ const char* tz = GeoIP_time_zone_by_country_and_region(
341
+ StringValuePtr(country), StringValuePtr(region));
342
+ return rb_str_new2(tz);
343
+ }
344
+
345
+ /* GeoIP *********************************************************************/
346
+
347
+ /* Returns the numeric form of an IP address.
348
+ *
349
+ * For example:
350
+ * 24.24.24.24 => 404232216
351
+ *
352
+ * This is used in order to be able to perform searches in CSV versions of the
353
+ * data files or in SQL records if the data has been put there.
354
+ */
355
+ VALUE rb_geoip_addr_to_num(VALUE self, VALUE addr) {
356
+ Check_Type(addr, T_STRING);
357
+ return UINT2NUM((unsigned int)GeoIP_addr_to_num(StringValuePtr(addr)));
358
+ }
359
+
360
+
361
+ VALUE rb_geoip_num_to_addr(VALUE self, VALUE num) {
362
+ VALUE num_type = TYPE(num);
363
+ switch(num_type) {
364
+ case T_FIXNUM: break;
365
+ case T_BIGNUM: break;
366
+ default: rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or Bignum)", rb_obj_classname(num));
367
+ }
368
+ return rb_str_new2((char*)GeoIP_num_to_addr((unsigned long)NUM2ULONG(num)));
369
+ }
370
+
371
+ void Init_geoip()
372
+ {
373
+ mGeoIP = rb_define_module("GeoIP");
374
+
375
+ rb_geoip_memory = ID2SYM(rb_intern("memory"));
376
+ rb_geoip_filesystem = ID2SYM(rb_intern("filesystem"));
377
+ rb_geoip_index = ID2SYM(rb_intern("index"));
378
+
379
+ mGeoIP_City = rb_define_class_under(mGeoIP, "City", rb_cObject);
380
+ rb_define_singleton_method(mGeoIP_City, "new", rb_geoip_city_new, -1);
381
+ rb_define_method( mGeoIP_City, "look_up", rb_geoip_city_look_up, 1);
382
+
383
+ mGeoIP_Country = rb_define_class_under(mGeoIP, "Country", rb_cObject);
384
+ rb_define_singleton_method(mGeoIP_Country, "new", rb_geoip_country_new, -1);
385
+ rb_define_method( mGeoIP_Country, "look_up", rb_geoip_country_look_up, 1);
386
+
387
+ mGeoIP_Organization = rb_define_class_under(mGeoIP, "Organization", rb_cObject);
388
+ rb_define_singleton_method(mGeoIP_Organization, "new", rb_geoip_org_new, -1);
389
+ rb_define_method( mGeoIP_Organization, "look_up", rb_geoip_org_look_up, 1);
390
+
391
+ mGeoIP_ISP = rb_define_class_under(mGeoIP, "ISP", rb_cObject);
392
+ rb_define_singleton_method(mGeoIP_ISP, "new", rb_geoip_isp_new, -1);
393
+ rb_define_method( mGeoIP_ISP, "look_up", rb_geoip_isp_look_up, 1);
394
+
395
+ mGeoIP_NetSpeed = rb_define_class_under(mGeoIP, "NetSpeed", rb_cObject);
396
+ rb_define_singleton_method(mGeoIP_NetSpeed, "new", rb_geoip_netspeed_new, -1);
397
+ rb_define_method( mGeoIP_NetSpeed, "look_up", rb_geoip_netspeed_look_up, 1);
398
+
399
+ mGeoIP_Domain = rb_define_class_under(mGeoIP, "Domain", rb_cObject);
400
+ rb_define_singleton_method(mGeoIP_Domain, "new", rb_geoip_domain_new, -1);
401
+ rb_define_method( mGeoIP_Domain, "look_up", rb_geoip_domain_look_up, 1);
402
+
403
+ mGeoIP_TimeZone = rb_define_class_under(mGeoIP, "TimeZone", rb_cObject);
404
+ rb_define_singleton_method(mGeoIP_TimeZone, "look_up", rb_geoip_timezone_lookup, 2);
405
+
406
+ rb_define_singleton_method(mGeoIP, "addr_to_num", rb_geoip_addr_to_num, 1);
407
+ rb_define_singleton_method(mGeoIP, "num_to_addr", rb_geoip_num_to_addr, 1);
408
+ }
data/test.rb ADDED
@@ -0,0 +1,175 @@
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
+ # timezone
70
+
71
+ def test_tz_from_country_region
72
+ assert_equal 'America/New_York', GeoIP::TimeZone.look_up('US', 'NY')
73
+ end
74
+ end
75
+
76
+ class GeoIPCityTest < Test::Unit::TestCase
77
+
78
+ def setup
79
+ ## Change me!
80
+ @dbfile = CITY_DB
81
+ end
82
+
83
+ def test_construction_default
84
+ db = GeoIP::City.new(@dbfile)
85
+
86
+ assert_raises TypeError do
87
+ db.look_up(nil)
88
+ end
89
+
90
+ h = db.look_up('24.24.24.24')
91
+ #debugger
92
+ assert_kind_of Hash, h
93
+ assert_equal 'New York', h[:city]
94
+ assert_equal 'United States', h[:country_name]
95
+ end
96
+
97
+ def test_construction_index
98
+ db = GeoIP::City.new(@dbfile, :index)
99
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
100
+ end
101
+
102
+ def test_construction_filesystem
103
+ db = GeoIP::City.new(@dbfile, :filesystem)
104
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
105
+ end
106
+
107
+ def test_construction_memory
108
+ db = GeoIP::City.new(@dbfile, :memory)
109
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
110
+ end
111
+
112
+ def test_construction_filesystem_check
113
+ db = GeoIP::City.new(@dbfile, :filesystem, true)
114
+ assert_look_up(db, '24.24.24.24', :city, 'New York')
115
+ end
116
+
117
+ def test_bad_db_file
118
+ assert_raises Errno::ENOENT do
119
+ GeoIP::City.new('/supposed-to-fail')
120
+ end
121
+ end
122
+
123
+ def test_character_encoding_converted_to_utf8_first
124
+ db = GeoIP::City.new(@dbfile, :filesystem, true)
125
+ assert_look_up(db, '201.85.50.148', :city, 'São Paulo')
126
+ end
127
+
128
+ end
129
+
130
+ class GeoIPOrgTest < Test::Unit::TestCase
131
+
132
+ def setup
133
+ ## Change me!
134
+ @dbfile = ORG_DB
135
+ end
136
+
137
+ def test_construction_default
138
+ db = GeoIP::Organization.new(@dbfile)
139
+
140
+ assert_raises TypeError do
141
+ db.look_up(nil)
142
+ end
143
+
144
+ h = db.look_up('24.24.24.24')
145
+ assert_kind_of Hash, h
146
+ assert_equal 'Road Runner', h[:name]
147
+ end
148
+
149
+ def test_construction_index
150
+ db = GeoIP::Organization.new(@dbfile, :index)
151
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
152
+ end
153
+
154
+ def test_construction_filesystem
155
+ db = GeoIP::Organization.new(@dbfile, :filesystem)
156
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
157
+ end
158
+
159
+ def test_construction_memory
160
+ db = GeoIP::Organization.new(@dbfile, :memory)
161
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
162
+ end
163
+
164
+ def test_construction_filesystem_check
165
+ db = GeoIP::Organization.new(@dbfile, :filesystem, true)
166
+ assert_look_up(db, '24.24.24.24', :name, 'Road Runner')
167
+ end
168
+
169
+ def test_bad_db_file
170
+ assert_raises Errno::ENOENT do
171
+ GeoIP::Organization.new('/supposed-to-fail')
172
+ end
173
+ end
174
+
175
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bitium-geoip-c
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Dahl
8
+ - Matt Todd
9
+ - Charles Brian Quinn
10
+ - Michael Sheakoski
11
+ - Silvio Quadri
12
+ - Andy Lindeman
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+ date: 2014-03-31 00:00:00.000000000 Z
17
+ dependencies: []
18
+ description: Generic GeoIP lookup tool. Based on the geoip_city RubyGem by Ryan Dahl
19
+ email:
20
+ - alindeman@gmail.com
21
+ - mtodd@highgroove.com
22
+ executables: []
23
+ extensions:
24
+ - extconf.rb
25
+ extra_rdoc_files: []
26
+ files:
27
+ - README.md
28
+ - Rakefile
29
+ - extconf.rb
30
+ - geoip.c
31
+ - test.rb
32
+ homepage: http://github.com/mtodd/geoip
33
+ licenses: []
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - "."
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.2.2
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: A Binding to the GeoIP C library
55
+ test_files:
56
+ - test.rb
57
+ has_rdoc: