geoip 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/geoip.rb +73 -33
  2. metadata +3 -3
data/lib/geoip.rb CHANGED
@@ -164,8 +164,7 @@ class GeoIP
164
164
  "AS","AS","OC","AS","AF","OC","AS","AS","SA","OC","AS","AF","EU","AF",
165
165
  "OC","NA","SA","AS","EU","SA","SA","SA","SA","AS","OC","OC","OC","AS",
166
166
  "AF","EU","AF","AF","AF","AF"]
167
-
168
- private
167
+ public
169
168
  # Edition enumeration:
170
169
  (GEOIP_COUNTRY_EDITION,
171
170
  GEOIP_CITY_EDITION_REV1,
@@ -178,6 +177,7 @@ class GeoIP
178
177
  GEOIP_ASNUM_EDITION,
179
178
  GEOIP_NETSPEED_EDITION,
180
179
  ) = *1..10
180
+ private
181
181
 
182
182
  COUNTRY_BEGIN = 16776960
183
183
  STATE_BEGIN_REV0 = 16700000
@@ -195,6 +195,7 @@ class GeoIP
195
195
  SEGMENT_RECORD_LENGTH = 3
196
196
 
197
197
  public
198
+ attr_reader :databaseType
198
199
  # Open the GeoIP database and determine the file format version
199
200
  #
200
201
  # +filename+ is a String holding the path to the GeoIP.dat file
@@ -300,51 +301,57 @@ class GeoIP
300
301
  # * The latitude
301
302
  # * The longitude
302
303
  # * The dma_code and area_code, if available (REV1 City database)
303
- def city(hostname)
304
- ip = hostname
305
- if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
306
- # Lookup IP address, we were given a name
307
- ip = IPSocket.getaddress(hostname)
308
- end
304
+ private
309
305
 
310
- # Convert numeric IP address to an integer
311
- ipnum = iptonum(ip)
312
- if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
313
- @databaseType != GEOIP_CITY_EDITION_REV1)
314
- throw "Invalid GeoIP database type, can't look up City by IP"
315
- end
316
- pos = seek_record(ipnum);
306
+ def read_city(pos, hostname = '', ip = '')
317
307
  @file.seek(pos + (2*@record_length-1) * @databaseSegments[0])
318
- record = @file.read(FULL_RECORD_LENGTH)
308
+ return nil if((record = @file.read(FULL_RECORD_LENGTH)).nil?)
319
309
 
320
310
  # The country code is the first byte:
321
311
  code = record[0]
322
312
  record = record[1..-1]
313
+ @iter_pos += 1 unless @iter_pos.nil?
323
314
 
315
+ spl = record.split("\x00", 4)
324
316
  # Get the region:
325
- region = record.sub(/\x00.*/, "")
326
- record.sub!(/[^\x00]*\x00/, '')
317
+ region = spl[0]
318
+ @iter_pos += (region.size + 1) unless @iter_pos.nil?
327
319
 
328
320
  # Get the city:
329
- city = record.sub(/\x00.*/, "")
330
- record.sub!(/[^\x00]*\x00/, '')
321
+ city = spl[1]
322
+ @iter_pos += (city.size + 1) unless @iter_pos.nil?
331
323
 
332
324
  # Get the postal code:
333
- postal_code = record.sub(/\x00.*/, "")
334
- record.sub!(/[^\x00]*\x00/, '')
325
+ postal_code = spl[2]
326
+ @iter_pos += (postal_code.size + 1) unless @iter_pos.nil?
335
327
 
328
+ record = spl[3]
336
329
  # Get the latitude/longitude:
337
- latitude = le_to_ui(record[0,3].unpack("C*"))/10000.0 - 180
338
- longitude = le_to_ui(record[3,3].unpack("C*"))/10000.0 - 180
330
+ if(record && record[0,3]) then
331
+ latitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
332
+ record = record[3..-1]
333
+ @iter_pos += 3 unless @iter_pos.nil?
334
+ else
335
+ latitude = ''
336
+ end
337
+ if(record && record[0,3]) then
338
+ longitude = le_to_ui(record[0,3].unpack('C*')) / 10000.0 - 180
339
+ record = record[3..-1]
340
+ @iter_pos += 3 unless @iter_pos.nil?
341
+ else
342
+ longitude = ''
343
+ end
339
344
 
340
- record = record[6..-1]
341
345
  us_area_codes = []
346
+ if(record && record[0,3]) then
342
347
  if (@databaseType == GEOIP_CITY_EDITION_REV1 &&
343
348
  CountryCode[code] == "US") # UNTESTED
344
- dmaarea_combo = le_to_ui(record[0,3].unpack("C*"))
345
- dma_code = dmaarea_combo/1000;
346
- area_code = dmaarea_combo%1000;
349
+ dmaarea_combo = le_to_ui(record[0,3].unpack('C*'))
350
+ dma_code = dmaarea_combo / 1000;
351
+ area_code = dmaarea_combo % 1000;
347
352
  us_area_codes = [ dma_code, area_code ]
353
+ @iter_pos += 3 unless @iter_pos.nil?
354
+ end
348
355
  end
349
356
 
350
357
  [ hostname, # Requested hostname
@@ -359,7 +366,39 @@ class GeoIP
359
366
  latitude,
360
367
  longitude,
361
368
  ] + us_area_codes
369
+ end
370
+ public
371
+ def city(hostname)
372
+ ip = hostname
373
+ if ip.kind_of?(String) && ip !~ /^[0-9.]*$/
374
+ # Lookup IP address, we were given a name
375
+ ip = IPSocket.getaddress(hostname)
376
+ end
377
+
378
+ # Convert numeric IP address to an integer
379
+ ipnum = iptonum(ip)
380
+ if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
381
+ @databaseType != GEOIP_CITY_EDITION_REV1)
382
+ throw "Invalid GeoIP database type, can't look up City by IP"
383
+ end
384
+ pos = seek_record(ipnum);
385
+ read_city(pos, hostname, ip)
386
+ end
362
387
 
388
+ def each
389
+ if (@databaseType != GEOIP_CITY_EDITION_REV0 &&
390
+ @databaseType != GEOIP_CITY_EDITION_REV1)
391
+ throw "Invalid GeoIP database type, can't iterate thru non-City database"
392
+ end
393
+
394
+ @iter_pos = @databaseSegments[0] + 1
395
+ num = 0
396
+ until((rec = read_city(@iter_pos)).nil?)
397
+ yield(rec)
398
+ print "#{num}: #{@iter_pos}\n" if((num += 1) % 1000 == 0)
399
+ end
400
+ @iter_pos = nil
401
+ self
363
402
  end
364
403
 
365
404
  private
@@ -375,21 +414,21 @@ class GeoIP
375
414
  # Binary search in the file.
376
415
  # Records are pairs of little-endian integers, each of @record_length.
377
416
  offset = 0
378
- mask = 2147483648
417
+ mask = 0x80000000
379
418
  31.downto(0) { |depth|
380
419
  @file.seek(@record_length * 2 * offset);
381
- buf = @file.read(@record_length*2);
420
+ buf = @file.read(@record_length * 2);
382
421
  buf.slice!(0...@record_length) if ((ipnum & mask) != 0)
383
422
  offset = le_to_ui(buf[0...@record_length].unpack("C*"))
384
423
  return offset if (offset >= @databaseSegments[0])
385
- mask = mask/2
424
+ mask >>= 1
386
425
  }
387
426
  end
388
427
 
389
428
  # Convert a big-endian array of numeric bytes to unsigned int
390
429
  def be_to_ui(s)
391
430
  s.inject(0) { |m, o|
392
- (m<<8)+o.to_i
431
+ (m << 8) + o.to_i
393
432
  }
394
433
  end
395
434
 
@@ -402,7 +441,8 @@ end
402
441
  if $0 == __FILE__
403
442
  g = GeoIP.new('/usr/share/GeoIP/GeoIP.dat');
404
443
 
444
+ req = ([GeoIP::GEOIP_CITY_EDITION_REV1, GeoIP::GEOIP_CITY_EDITION_REV0].include?(g.databaseType)) ? :city : :country
405
445
  ARGV.each { |a|
406
- p g.country(a)
446
+ p g.send(req, a)
407
447
  }
408
448
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.4
2
+ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: geoip
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.0
7
- date: 2005-04-27
6
+ version: 0.3.0
7
+ date: 2006-09-25
8
8
  summary: "GeoIP looks up a GeoIP database to provide geographical data for an IP address
9
9
  or Internet hostname. The free version of the GeoIP database available from
10
10
  www.maxmind.com only contains country information. This library supports that