geoip 0.8.5 → 0.8.6

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 (2) hide show
  1. data/lib/geoip.rb +32 -21
  2. metadata +3 -3
data/lib/geoip.rb CHANGED
@@ -43,9 +43,14 @@ $:.unshift File.dirname(__FILE__)
43
43
  #=end
44
44
  require 'thread' # Needed for Mutex
45
45
  require 'socket'
46
+ begin
47
+ require 'io/extra' # for IO.pread
48
+ rescue LoadError
49
+ # oh well, hope they're not forking after initializing
50
+ end
46
51
 
47
52
  class GeoIP
48
- VERSION = "0.8.5"
53
+ VERSION = "0.8.6"
49
54
  private
50
55
  CountryCode = [
51
56
  "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
@@ -429,7 +434,7 @@ class GeoIP
429
434
  # +filename+ is a String holding the path to the GeoIP.dat file
430
435
  # +options+ is an integer holding caching flags (unimplemented)
431
436
  def initialize(filename, flags = 0)
432
- @mutex = Mutex.new
437
+ @mutex = IO.respond_to?(:pread) ? false : Mutex.new
433
438
  @flags = flags
434
439
  @databaseType = GEOIP_COUNTRY_EDITION
435
440
  @record_length = STANDARD_RECORD_LENGTH
@@ -530,11 +535,9 @@ class GeoIP
530
535
  private
531
536
 
532
537
  def read_city(pos, hostname = '', ip = '')
533
- record = ""
534
- @mutex.synchronize {
535
- @file.seek(pos + (2*@record_length-1) * @databaseSegments[0])
536
- return nil unless record = @file.read(FULL_RECORD_LENGTH)
537
- }
538
+ off = pos + (2*@record_length-1) * @databaseSegments[0]
539
+ record = atomic_read(FULL_RECORD_LENGTH, off)
540
+ return nil unless record && record.size == FULL_RECORD_LENGTH
538
541
 
539
542
  # The country code is the first byte:
540
543
  code = record[0]
@@ -656,11 +659,8 @@ class GeoIP
656
659
  throw "Invalid GeoIP database type, can't look up Organization/ISP by IP"
657
660
  end
658
661
  pos = seek_record(ipnum);
659
- record = ""
660
- @mutex.synchronize {
661
- @file.seek(pos + (2*@record_length-1) * @databaseSegments[0])
662
- record = @file.read(MAX_ORG_RECORD_LENGTH)
663
- }
662
+ off = pos + (2*@record_length-1) * @databaseSegments[0]
663
+ record = atomic_read(MAX_ORG_RECORD_LENGTH, off)
664
664
  record = record.sub(/\000.*/n, '')
665
665
  record
666
666
  end
@@ -687,11 +687,8 @@ class GeoIP
687
687
  throw "Invalid GeoIP database type, can't look up ASN by IP"
688
688
  end
689
689
  pos = seek_record(ipnum);
690
- record = ""
691
- @mutex.synchronize {
692
- @file.seek(pos + (2*@record_length-1) * @databaseSegments[0])
693
- record = @file.read(MAX_ASN_RECORD_LENGTH)
694
- }
690
+ off = pos + (2*@record_length-1) * @databaseSegments[0]
691
+ record = atomic_read(MAX_ASN_RECORD_LENGTH, off)
695
692
  record = record.sub(/\000.*/n, '')
696
693
 
697
694
  if record =~ /^(AS\d+)\s(.*)$/
@@ -740,10 +737,8 @@ class GeoIP
740
737
  offset = 0
741
738
  mask = 0x80000000
742
739
  31.downto(0) { |depth|
743
- buf = @mutex.synchronize {
744
- @file.seek(@record_length * 2 * offset);
745
- @file.read(@record_length * 2);
746
- }
740
+ off = @record_length * 2 * offset
741
+ buf = atomic_read(@record_length * 2, off)
747
742
  buf.slice!(0...@record_length) if ((ipnum & mask) != 0)
748
743
  offset = le_to_ui(buf[0...@record_length].unpack("C*"))
749
744
  return offset if (offset >= @databaseSegments[0])
@@ -762,6 +757,22 @@ class GeoIP
762
757
  def le_to_ui(s)
763
758
  be_to_ui(s.reverse)
764
759
  end
760
+
761
+ # reads +length+ bytes from +offset+ as atomically as possible
762
+ # if IO.pread is available, it'll use that (making it both multithread
763
+ # and multiprocess-safe).  Otherwise we'll use a mutex to synchronize
764
+ # access (only providing protection against multiple threads, but not
765
+ # file descriptors shared across multiple processes).
766
+ def atomic_read(length, offset)
767
+ if @mutex
768
+ @mutex.synchronize {
769
+ @file.seek(offset)
770
+ @file.read(length)
771
+ }
772
+ else
773
+ IO.pread(@file.fileno, length, offset)
774
+ end
775
+ end
765
776
  end
766
777
 
767
778
  if $0 == __FILE__
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geoip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.5
4
+ version: 0.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clifford Heath
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-11-09 00:00:00 +00:00
13
+ date: 2009-11-12 00:00:00 +00:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -21,7 +21,7 @@ dependencies:
21
21
  requirements:
22
22
  - - ">="
23
23
  - !ruby/object:Gem::Version
24
- version: 2.3.2
24
+ version: 2.3.3
25
25
  version:
26
26
  description: |-
27
27
  GeoIP searches a GeoIP database for a given host or IP address, and