geoip 0.8.5 → 0.8.6

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 +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