geoipdb 0.1.4
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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +18 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/ext/build.sh +1 -0
- data/ext/extconf.rb +5 -0
- data/ext/geoipdb.c +109 -0
- data/ext/ipdb.c +604 -0
- data/ext/ipdb.h +69 -0
- data/ext/test.c +42 -0
- data/geoipdb.gemspec +71 -0
- data/lib/geoipdb.rb +0 -0
- data/sample_data/cities.csv +7 -0
- data/sample_data/citiess_corrupt.csv +8 -0
- data/sample_data/ip_ranges.csv +11 -0
- data/sample_data/ip_ranges_corrupt.csv +20 -0
- data/spec/geoipdb_spec.rb +37 -0
- data/spec/spec_helper.rb +12 -0
- metadata +150 -0
    
        data/.document
    ADDED
    
    
    
        data/.rspec
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            --color
         | 
    
        data/Gemfile
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            source "http://rubygems.org"
         | 
| 2 | 
            +
            # Add dependencies required to use your gem here.
         | 
| 3 | 
            +
            # Example:
         | 
| 4 | 
            +
            #   gem "activesupport", ">= 2.3.5"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # Add dependencies to develop your gem here.
         | 
| 7 | 
            +
            # Include everything needed to run rake, tests, features, etc.
         | 
| 8 | 
            +
            group :development do
         | 
| 9 | 
            +
              gem "rspec", "~> 2.1.0"
         | 
| 10 | 
            +
              gem "bundler", "~> 1.0.0"
         | 
| 11 | 
            +
              gem "jeweler", "~> 1.5.1"
         | 
| 12 | 
            +
              gem "rcov", ">= 0"
         | 
| 13 | 
            +
            end
         | 
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright (c) 2010 Eugen Martin
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README.markdown
    ADDED
    
    | @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            # geoipdb: fast (in memory!) geo location db.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions. 
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              * Returns a GeoLocation to a given IP. 
         | 
| 6 | 
            +
              * Reads Data from CSV-Files and uses internal binary caching.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ## Usage
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                db = GeoIpDb.init "city_codes.csv", "ip_city.txt", "ip_city.cache"
         | 
| 11 | 
            +
                location_hash = db.city_by_ip("178.0.0.1")
         | 
| 12 | 
            +
                # => {"name"=>"eschborn", "country"=>"deu", "lng"=>8.55, "lat"=>50.133333} 
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            == Copyright
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            Copyright (c) 2010 Eugen Martin. See LICENSE.txt for
         | 
| 17 | 
            +
            further details.
         | 
| 18 | 
            +
             | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'bundler'
         | 
| 3 | 
            +
            begin
         | 
| 4 | 
            +
              Bundler.setup(:default, :development)
         | 
| 5 | 
            +
            rescue Bundler::BundlerError => e
         | 
| 6 | 
            +
              $stderr.puts e.message
         | 
| 7 | 
            +
              $stderr.puts "Run `bundle install` to install missing gems"
         | 
| 8 | 
            +
              exit e.status_code
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
            require 'rake'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            require 'jeweler'
         | 
| 13 | 
            +
            Jeweler::Tasks.new do |gem|
         | 
| 14 | 
            +
              # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
         | 
| 15 | 
            +
              gem.name = "geoipdb"
         | 
| 16 | 
            +
              gem.homepage = "http://github.com/olgen/geoipdb"
         | 
| 17 | 
            +
              gem.license = "MIT"
         | 
| 18 | 
            +
              gem.summary = %Q{Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.}
         | 
| 19 | 
            +
              gem.description = %Q{Returns a GeoLocation to a given IP. Reads Data from CSV-Files and uses internal binary caching.}
         | 
| 20 | 
            +
              gem.email = "eugeniusmartinus@googlemail.com"
         | 
| 21 | 
            +
              gem.authors = ["Eugen Martin"]
         | 
| 22 | 
            +
              gem.extensions   = ['ext/extconf.rb']
         | 
| 23 | 
            +
              gem.require_path = "ext"  
         | 
| 24 | 
            +
            end
         | 
| 25 | 
            +
            Jeweler::RubygemsDotOrgTasks.new
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            require 'rspec/core'
         | 
| 28 | 
            +
            require 'rspec/core/rake_task'
         | 
| 29 | 
            +
            RSpec::Core::RakeTask.new(:spec) do |spec|
         | 
| 30 | 
            +
              spec.pattern = FileList['spec/**/*_spec.rb']
         | 
| 31 | 
            +
            end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            RSpec::Core::RakeTask.new(:rcov) do |spec|
         | 
| 34 | 
            +
              spec.pattern = 'spec/**/*_spec.rb'
         | 
| 35 | 
            +
              spec.rcov = true
         | 
| 36 | 
            +
            end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            task :default => :spec
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            require 'rake/rdoctask'
         | 
| 41 | 
            +
            Rake::RDocTask.new do |rdoc|
         | 
| 42 | 
            +
              version = File.exist?('VERSION') ? File.read('VERSION') : ""
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              rdoc.rdoc_dir = 'rdoc'
         | 
| 45 | 
            +
              rdoc.title = "geoipdb #{version}"
         | 
| 46 | 
            +
              rdoc.rdoc_files.include('README*')
         | 
| 47 | 
            +
              rdoc.rdoc_files.include('lib/**/*.rb')
         | 
| 48 | 
            +
            end
         | 
    
        data/VERSION
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            0.1.4
         | 
    
        data/ext/build.sh
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            gcc -Wall -o test test.c ipdb.c ipdb.h
         | 
    
        data/ext/extconf.rb
    ADDED
    
    
    
        data/ext/geoipdb.c
    ADDED
    
    | @@ -0,0 +1,109 @@ | |
| 1 | 
            +
            #include "ipdb.h"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #include "ruby.h"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            /** 
         | 
| 6 | 
            +
            Ruby Wrapper
         | 
| 7 | 
            +
            */
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            typedef struct geipdb {
         | 
| 10 | 
            +
              IPDB *db;
         | 
| 11 | 
            +
            } geoipdb;
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            static VALUE cGeoIpDb;
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            VALUE method_hello_world(VALUE self);
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            // free the memory used by the db, called by the Ruby-GC
         | 
| 18 | 
            +
            void geoipdb_free(geoipdb *gi) {
         | 
| 19 | 
            +
              printf("Freeing memory for the GeoIpDb.. \n");
         | 
| 20 | 
            +
              if(gi == NULL)
         | 
| 21 | 
            +
                return;
         | 
| 22 | 
            +
              if (gi->db != NULL){
         | 
| 23 | 
            +
                if(gi->db->cities != NULL ){
         | 
| 24 | 
            +
                  printf("..freeing cities \n");
         | 
| 25 | 
            +
                  free(gi->db->cities);
         | 
| 26 | 
            +
                  gi->db->cities = NULL;
         | 
| 27 | 
            +
                }
         | 
| 28 | 
            +
                if(gi->db->ranges != NULL ){
         | 
| 29 | 
            +
                  printf("..freeing ranges \n");
         | 
| 30 | 
            +
                  free(gi->db->ranges);
         | 
| 31 | 
            +
                  gi->db->ranges = NULL;
         | 
| 32 | 
            +
                }
         | 
| 33 | 
            +
                if(gi->db != NULL){
         | 
| 34 | 
            +
                  printf("..freeing ipdb \n");      
         | 
| 35 | 
            +
                  free(gi->db);      
         | 
| 36 | 
            +
                }
         | 
| 37 | 
            +
              }
         | 
| 38 | 
            +
            }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
            VALUE ipdb_init(VALUE self, VALUE cities_file_name, VALUE ranges_file_name, VALUE cache_file_name) {
         | 
| 42 | 
            +
              geoipdb *gi;
         | 
| 43 | 
            +
              
         | 
| 44 | 
            +
              Check_Type(cities_file_name, T_STRING);
         | 
| 45 | 
            +
              Check_Type(ranges_file_name, T_STRING);
         | 
| 46 | 
            +
              Check_Type(cache_file_name, T_STRING);
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
              char *cities_csv_file = RSTRING(cities_file_name)->ptr;
         | 
| 49 | 
            +
              char *ranges_csv_file = RSTRING(ranges_file_name)->ptr;
         | 
| 50 | 
            +
              char *cache_file =      RSTRING(cache_file_name)->ptr;  
         | 
| 51 | 
            +
              
         | 
| 52 | 
            +
              gi = malloc(sizeof(geoipdb));
         | 
| 53 | 
            +
              
         | 
| 54 | 
            +
              gi->db= init_db(cities_csv_file, ranges_csv_file, cache_file);
         | 
| 55 | 
            +
              
         | 
| 56 | 
            +
              if(gi->db == NULL)
         | 
| 57 | 
            +
              {
         | 
| 58 | 
            +
                if(DEBUG)
         | 
| 59 | 
            +
                  printf("Could not init DB!\n");
         | 
| 60 | 
            +
                /*
         | 
| 61 | 
            +
                  TODO: Add geoipdb_free in this case.. though not important for production...
         | 
| 62 | 
            +
                */
         | 
| 63 | 
            +
                return Qnil;
         | 
| 64 | 
            +
              }else{
         | 
| 65 | 
            +
                if(DEBUG)
         | 
| 66 | 
            +
                  printf("\nDB Init completed!\n");
         | 
| 67 | 
            +
                return(Data_Wrap_Struct(cGeoIpDb, 0, geoipdb_free, gi));    
         | 
| 68 | 
            +
              }
         | 
| 69 | 
            +
            }
         | 
| 70 | 
            +
             | 
| 71 | 
            +
             | 
| 72 | 
            +
            VALUE city_to_hash(City * city){
         | 
| 73 | 
            +
              VALUE hash = rb_hash_new();       
         | 
| 74 | 
            +
              // return a ruby-hash with the needed data
         | 
| 75 | 
            +
              rb_hash_aset(hash, rb_str_new2("name"), rb_str_new2(city->name));  
         | 
| 76 | 
            +
              rb_hash_aset(hash, rb_str_new2("country"), rb_str_new2(city->country_iso2));      
         | 
| 77 | 
            +
              rb_hash_aset(hash, rb_str_new2("lat"), rb_float_new(city->lat));  
         | 
| 78 | 
            +
              rb_hash_aset(hash, rb_str_new2("lng"), rb_float_new(city->lng));      
         | 
| 79 | 
            +
              rb_hash_aset(hash, rb_str_new2("city_code"), INT2FIX(city->city_code));        
         | 
| 80 | 
            +
              return hash;
         | 
| 81 | 
            +
            }
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            VALUE ipdb_city_by_ip(VALUE self, VALUE ip_string){
         | 
| 84 | 
            +
              char *ip = RSTRING(ip_string)->ptr;
         | 
| 85 | 
            +
              geoipdb *gi;
         | 
| 86 | 
            +
              
         | 
| 87 | 
            +
              Data_Get_Struct(self, geoipdb, gi);
         | 
| 88 | 
            +
              City * city = city_by_ip(gi->db, ip);  
         | 
| 89 | 
            +
              if(city == NULL)
         | 
| 90 | 
            +
              {
         | 
| 91 | 
            +
                // printf("Could not find city for ip: %s\n", ip);
         | 
| 92 | 
            +
                return Qnil;
         | 
| 93 | 
            +
              }else{
         | 
| 94 | 
            +
                // printf("Found city for ip: %s\n", ip);
         | 
| 95 | 
            +
                // print_city(city);
         | 
| 96 | 
            +
                return city_to_hash(city);
         | 
| 97 | 
            +
                // create a hash to return to ruby:
         | 
| 98 | 
            +
              }
         | 
| 99 | 
            +
            }
         | 
| 100 | 
            +
             | 
| 101 | 
            +
             | 
| 102 | 
            +
             | 
| 103 | 
            +
            void Init_geoipdb(void)
         | 
| 104 | 
            +
            {
         | 
| 105 | 
            +
              //Erstelle die Klasse cGeoIpDb als Subklasse von Object
         | 
| 106 | 
            +
              cGeoIpDb = rb_define_class( "GeoIpDb", rb_cObject);
         | 
| 107 | 
            +
              rb_define_singleton_method( cGeoIpDb, "init",        ipdb_init, 3); 
         | 
| 108 | 
            +
              rb_define_method(           cGeoIpDb, "city_by_ip",  ipdb_city_by_ip, 1);  
         | 
| 109 | 
            +
            }
         | 
    
        data/ext/ipdb.c
    ADDED
    
    | @@ -0,0 +1,604 @@ | |
| 1 | 
            +
            #include "ipdb.h"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #include <search.h>
         | 
| 4 | 
            +
            #include <stdio.h>
         | 
| 5 | 
            +
            #include <string.h>
         | 
| 6 | 
            +
            #include <stdlib.h>
         | 
| 7 | 
            +
            #include <sys/time.h>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
            const char country_iso2_codes[253][3] = { "--","ap","eu","ad","ae","af","ag","ai","al","am","an",
         | 
| 13 | 
            +
            	"ao","aq","ar","as","at","au","aw","az","ba","bb",
         | 
| 14 | 
            +
            	"bd","be","bf","bg","bh","bi","bj","bm","bn","bo",
         | 
| 15 | 
            +
            	"br","bs","bt","bv","bw","by","bz","ca","cc","cd",
         | 
| 16 | 
            +
            	"cf","cg","ch","ci","ck","cl","cm","cn","co","cr",
         | 
| 17 | 
            +
            	"cu","cv","cx","cy","cz","de","dj","dk","dm","do",
         | 
| 18 | 
            +
            	"dz","ec","ee","eg","eh","er","es","et","fi","fj",
         | 
| 19 | 
            +
            	"fk","fm","fo","fr","fx","ga","gb","gd","ge","gf",
         | 
| 20 | 
            +
            	"gh","gi","gl","gm","gn","gp","gq","gr","gs","gt",
         | 
| 21 | 
            +
            	"gu","gw","gy","hk","hm","hn","hr","ht","hu","id",
         | 
| 22 | 
            +
            	"ie","il","in","io","iq","ir","is","it","jm","jo",
         | 
| 23 | 
            +
            	"jp","ke","kg","kh","ki","km","kn","kp","kr","kw",
         | 
| 24 | 
            +
            	"ky","kz","la","lb","lc","li","lk","lr","ls","lt",
         | 
| 25 | 
            +
            	"lu","lv","ly","ma","mc","md","mg","mh","mk","ml",
         | 
| 26 | 
            +
            	"mm","mn","mo","mp","mq","mr","ms","mt","mu","mv",
         | 
| 27 | 
            +
            	"mw","mx","my","mz","na","nc","ne","nf","ng","ni",
         | 
| 28 | 
            +
            	"nl","no","np","nr","nu","nz","om","pa","pe","pf",
         | 
| 29 | 
            +
            	"pg","ph","pk","pl","pm","pn","pr","ps","pt","pw",
         | 
| 30 | 
            +
            	"py","qa","re","ro","ru","rw","sa","sb","sc","sd",
         | 
| 31 | 
            +
            	"se","sg","sh","si","sj","sk","sl","sm","sn","so",
         | 
| 32 | 
            +
            	"sr","st","sv","sy","sz","tc","td","tf","tg","th",
         | 
| 33 | 
            +
            	"tj","tk","tm","tn","to","tl","tr","tt","tv","tw",
         | 
| 34 | 
            +
            	"tz","ua","ug","um","us","uy","uz","va","vc","ve",
         | 
| 35 | 
            +
            	"vg","vi","vn","vu","wf","ws","ye","yt","rs","za",
         | 
| 36 | 
            +
            	"zm","me","zw","a1","a2","o1","ax","gg","im","je",
         | 
| 37 | 
            +
              "bl","mf"};
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            static const unsigned num_countries = (unsigned)(sizeof(country_iso2_codes)/sizeof(country_iso2_codes[0]));
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            const char country_iso3_codes[253][4] = { "--","ap","eu","and","are","afg","atg","aia","alb","arm","ant",
         | 
| 42 | 
            +
            	"ago","aq","arg","asm","aut","aus","abw","aze","bih","brb",
         | 
| 43 | 
            +
            	"bgd","bel","bfa","bgr","bhr","bdi","ben","bmu","brn","bol",
         | 
| 44 | 
            +
            	"bra","bhs","btn","bv","bwa","blr","blz","can","cc","cod",
         | 
| 45 | 
            +
            	"caf","cog","che","civ","cok","chl","cmr","chn","col","cri",
         | 
| 46 | 
            +
            	"cub","cpv","cx","cyp","cze","deu","dji","dnk","dma","dom",
         | 
| 47 | 
            +
            	"dza","ecu","est","egy","esh","eri","esp","eth","fin","fji",
         | 
| 48 | 
            +
            	"flk","fsm","fro","fra","fx","gab","gbr","grd","geo","guf",
         | 
| 49 | 
            +
            	"gha","gib","grl","gmb","gin","glp","gnq","grc","gs","gtm",
         | 
| 50 | 
            +
            	"gum","gnb","guy","hkg","hm","hnd","hrv","hti","hun","idn",
         | 
| 51 | 
            +
            	"irl","isr","ind","io","irq","irn","isl","ita","jam","jor",
         | 
| 52 | 
            +
            	"jpn","ken","kgz","khm","kir","com","kna","prk","kor","kwt",
         | 
| 53 | 
            +
            	"cym","kaz","lao","lbn","lca","lie","lka","lbr","lso","ltu",
         | 
| 54 | 
            +
            	"lux","lva","lby","mar","mco","mda","mdg","mhl","mkd","mli",
         | 
| 55 | 
            +
            	"mmr","mng","mac","mnp","mtq","mrt","msr","mlt","mus","mdv",
         | 
| 56 | 
            +
            	"mwi","mex","mys","moz","nam","ncl","ner","nfk","nga","nic",
         | 
| 57 | 
            +
            	"nld","nor","npl","nru","niu","nzl","omn","pan","per","pyf",
         | 
| 58 | 
            +
            	"png","phl","pak","pol","spm","pcn","pri","pse","prt","plw",
         | 
| 59 | 
            +
            	"pry","qat","reu","rou","rus","rwa","sau","slb","syc","sdn",
         | 
| 60 | 
            +
            	"swe","sgp","shn","svn","sjm","svk","sle","smr","sen","som",
         | 
| 61 | 
            +
            	"sur","stp","slv","syr","swz","tca","tcd","tf","tgo","tha",
         | 
| 62 | 
            +
            	"tjk","tkl","tkm","tun","ton","tls","tur","tto","tuv","twn",
         | 
| 63 | 
            +
            	"tza","ukr","uga","um","usa","ury","uzb","vat","vct","ven",
         | 
| 64 | 
            +
            	"vgb","vir","vnm","vut","wlf","wsm","yem","yt","srb","zaf",
         | 
| 65 | 
            +
            	"zmb","mne","zwe","a1","a2","o1","ala","ggy","imn","jey",
         | 
| 66 | 
            +
              "blm","maf"};
         | 
| 67 | 
            +
             | 
| 68 | 
            +
             | 
| 69 | 
            +
            void 
         | 
| 70 | 
            +
            print_range(const IpRange* e){
         | 
| 71 | 
            +
              printf( "from: %lu, to:%lu ->City-idx: %i \n",e->from, e->to,e->city_index );    
         | 
| 72 | 
            +
            }
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            void 
         | 
| 75 | 
            +
            print_ranges(IPDB * db){
         | 
| 76 | 
            +
              int i;
         | 
| 77 | 
            +
              for(i = 0; i < db->ranges_count; ++i)
         | 
| 78 | 
            +
              {
         | 
| 79 | 
            +
                print_range(&(db->ranges[i]));
         | 
| 80 | 
            +
              }
         | 
| 81 | 
            +
            }
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            void 
         | 
| 84 | 
            +
            print_city(const City * e){
         | 
| 85 | 
            +
              if(e == NULL)
         | 
| 86 | 
            +
              {
         | 
| 87 | 
            +
                return;
         | 
| 88 | 
            +
              }
         | 
| 89 | 
            +
              printf( "City: code:%i, name:%s, country: %s, lat: %10.7f, lng: %10.7f  \n",e->city_code, e->name, e->country_iso3, e->lat, e->lng );    
         | 
| 90 | 
            +
            }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            void 
         | 
| 93 | 
            +
            print_cities(IPDB * db){
         | 
| 94 | 
            +
              int i;
         | 
| 95 | 
            +
              for(i = 0; i < db->cities_count; ++i)
         | 
| 96 | 
            +
              {
         | 
| 97 | 
            +
                print_city(&(db->cities[i]));
         | 
| 98 | 
            +
              }
         | 
| 99 | 
            +
            }
         | 
| 100 | 
            +
             | 
| 101 | 
            +
             | 
| 102 | 
            +
             | 
| 103 | 
            +
            void print_stats(IPDB * db){
         | 
| 104 | 
            +
              printf("DB STATS: \n");
         | 
| 105 | 
            +
              printf("\tCities: %i\n", db->cities_count);
         | 
| 106 | 
            +
              printf("\tRanges: %i\n", db->ranges_count);  
         | 
| 107 | 
            +
            }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            double 
         | 
| 110 | 
            +
            get_time(struct timeval *tim){
         | 
| 111 | 
            +
              gettimeofday(tim, NULL);
         | 
| 112 | 
            +
              return tim->tv_sec+(tim->tv_usec/1000000.0);
         | 
| 113 | 
            +
            }
         | 
| 114 | 
            +
             | 
| 115 | 
            +
             | 
| 116 | 
            +
            unsigned long
         | 
| 117 | 
            +
            ip_to_int(const char *addr){
         | 
| 118 | 
            +
            	unsigned int    c, octet, t;
         | 
| 119 | 
            +
            	unsigned long   ipnum;
         | 
| 120 | 
            +
            	int             i = 3;
         | 
| 121 | 
            +
             | 
| 122 | 
            +
            	octet = ipnum = 0;
         | 
| 123 | 
            +
            	while ((c = *addr++)) {
         | 
| 124 | 
            +
            		if (c == '.') {
         | 
| 125 | 
            +
            			if (octet > 255)
         | 
| 126 | 
            +
            				return 0;
         | 
| 127 | 
            +
            			ipnum <<= 8;
         | 
| 128 | 
            +
            			ipnum += octet;
         | 
| 129 | 
            +
            			i--;
         | 
| 130 | 
            +
            			octet = 0;
         | 
| 131 | 
            +
            		} else {
         | 
| 132 | 
            +
            			t = octet;
         | 
| 133 | 
            +
            			octet <<= 3;
         | 
| 134 | 
            +
            			octet += t;
         | 
| 135 | 
            +
            			octet += t;
         | 
| 136 | 
            +
            			c -= '0';
         | 
| 137 | 
            +
            			if (c > 9)
         | 
| 138 | 
            +
            				return 0;
         | 
| 139 | 
            +
            			octet += c;
         | 
| 140 | 
            +
            		}
         | 
| 141 | 
            +
            	}
         | 
| 142 | 
            +
            	if ((octet > 255) || (i != 0))
         | 
| 143 | 
            +
            		return 0;
         | 
| 144 | 
            +
            	ipnum <<= 8;
         | 
| 145 | 
            +
            	return ipnum + octet;
         | 
| 146 | 
            +
            }
         | 
| 147 | 
            +
             | 
| 148 | 
            +
             | 
| 149 | 
            +
            // Function to compare 
         | 
| 150 | 
            +
            // - either two ip-ranges: i.e.: a(from...to) <=> b(from...to)
         | 
| 151 | 
            +
            // - or a ip(i.e. range without to) and an ip-range: i.e. a(from...NULL) <=> b(from...to); a(from...to) <=> b(from ... NULL)
         | 
| 152 | 
            +
            int compare_ranges(const void *fa, const void *fb) {
         | 
| 153 | 
            +
              if(fa == NULL)
         | 
| 154 | 
            +
              {
         | 
| 155 | 
            +
                printf("FA IS NULL!!!\n");
         | 
| 156 | 
            +
                return 0;
         | 
| 157 | 
            +
              }
         | 
| 158 | 
            +
              if(fb == NULL)
         | 
| 159 | 
            +
              {
         | 
| 160 | 
            +
                printf("FB IS NULL!!!\n");
         | 
| 161 | 
            +
                return 0;
         | 
| 162 | 
            +
              }
         | 
| 163 | 
            +
             | 
| 164 | 
            +
             | 
| 165 | 
            +
              const IpRange *a = (IpRange *) fa;
         | 
| 166 | 
            +
              const IpRange *b = (IpRange *) fb;  
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              // printf("\tComparing: a:");
         | 
| 169 | 
            +
              // print_range(a);
         | 
| 170 | 
            +
              // printf(" with b:");
         | 
| 171 | 
            +
              // print_range(b);
         | 
| 172 | 
            +
              // printf("\n");
         | 
| 173 | 
            +
             | 
| 174 | 
            +
              if(a->from>0 && a->to>0 && b->from>0 && b->to>0){ //regular case: both entries are ranges
         | 
| 175 | 
            +
                if(a->to  <  b->from)    {
         | 
| 176 | 
            +
                  return -1;
         | 
| 177 | 
            +
                }else if(a->from > b->to){
         | 
| 178 | 
            +
                  return +1;
         | 
| 179 | 
            +
                }else{
         | 
| 180 | 
            +
                  return 0;
         | 
| 181 | 
            +
                }
         | 
| 182 | 
            +
              }else if(a->to == 0 && b->to>0){//a is a search_object
         | 
| 183 | 
            +
                if(a->from  <  b->from)    {
         | 
| 184 | 
            +
                  return -1;
         | 
| 185 | 
            +
                }else if(a->from > b->to){
         | 
| 186 | 
            +
                  return +1;
         | 
| 187 | 
            +
                }else{
         | 
| 188 | 
            +
                  return 0;
         | 
| 189 | 
            +
                }
         | 
| 190 | 
            +
              }else if(b->to == 0 && a->to>0){//b is a search_object
         | 
| 191 | 
            +
                if(b->from  <  a->from){
         | 
| 192 | 
            +
                  return -1;
         | 
| 193 | 
            +
                }else if(b->from > a->to){
         | 
| 194 | 
            +
                  return +1;
         | 
| 195 | 
            +
                }else{
         | 
| 196 | 
            +
                  return 0;
         | 
| 197 | 
            +
                }
         | 
| 198 | 
            +
              }else if(a->to == 0 && b->to == 0){ //both are search objects - this should not happen!
         | 
| 199 | 
            +
                return a->from - b->from;
         | 
| 200 | 
            +
              }
         | 
| 201 | 
            +
              return 0;
         | 
| 202 | 
            +
            }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
             | 
| 205 | 
            +
            int 
         | 
| 206 | 
            +
            compare_cities(const void *a, const void *b){
         | 
| 207 | 
            +
              const City city_a = *(City*)a;
         | 
| 208 | 
            +
              const City city_b = * (City*) b;
         | 
| 209 | 
            +
              // sort cities by city_code
         | 
| 210 | 
            +
              return city_a.city_code - city_b.city_code;
         | 
| 211 | 
            +
            }
         | 
| 212 | 
            +
             | 
| 213 | 
            +
            void
         | 
| 214 | 
            +
            sort_cities(IPDB * db){
         | 
| 215 | 
            +
              if(DEBUG)
         | 
| 216 | 
            +
                printf("Sorting %i Cities in db...\n", db->cities_count);
         | 
| 217 | 
            +
              
         | 
| 218 | 
            +
              struct timeval tim;
         | 
| 219 | 
            +
              double t1 = get_time(&tim);  
         | 
| 220 | 
            +
              
         | 
| 221 | 
            +
              qsort(db->cities,db->cities_count,sizeof(City), compare_cities);  
         | 
| 222 | 
            +
              if(DEBUG)
         | 
| 223 | 
            +
                printf("\n Sorting cities needed %.6lf seconds\n", get_time(&tim)-t1);  
         | 
| 224 | 
            +
            }
         | 
| 225 | 
            +
             | 
| 226 | 
            +
             | 
| 227 | 
            +
            int // returns a city-inde
         | 
| 228 | 
            +
            city_index_by_code(IPDB * db, uint16 city_code){
         | 
| 229 | 
            +
              City *search, *result;
         | 
| 230 | 
            +
              search = malloc(sizeof(City));
         | 
| 231 | 
            +
              search->city_code = city_code;
         | 
| 232 | 
            +
              result = (City*) bsearch(search, db->cities, db->cities_count, sizeof(City), compare_cities);
         | 
| 233 | 
            +
              
         | 
| 234 | 
            +
              if(search != NULL)
         | 
| 235 | 
            +
                free(search);
         | 
| 236 | 
            +
              
         | 
| 237 | 
            +
              if(result == NULL)
         | 
| 238 | 
            +
              {
         | 
| 239 | 
            +
                if(DEBUG)
         | 
| 240 | 
            +
                  printf("Could not find searched city with code: %i \n", city_code);
         | 
| 241 | 
            +
                return -1;
         | 
| 242 | 
            +
              }else{
         | 
| 243 | 
            +
                // printf("Found result: \t");
         | 
| 244 | 
            +
                // print_city(result);
         | 
| 245 | 
            +
                int index;
         | 
| 246 | 
            +
                index = (result - db->cities);
         | 
| 247 | 
            +
                // printf("Found index: %i\n", index);
         | 
| 248 | 
            +
                return index;
         | 
| 249 | 
            +
              }
         | 
| 250 | 
            +
            }
         | 
| 251 | 
            +
             | 
| 252 | 
            +
             | 
| 253 | 
            +
            City * 
         | 
| 254 | 
            +
            city_by_ip(IPDB *db, char *ip){
         | 
| 255 | 
            +
              IpRange * search, *result;
         | 
| 256 | 
            +
              search = (IpRange *)malloc(sizeof(IpRange));
         | 
| 257 | 
            +
              void * res;
         | 
| 258 | 
            +
             | 
| 259 | 
            +
              // print_stats(db);
         | 
| 260 | 
            +
              
         | 
| 261 | 
            +
              if(db == NULL)
         | 
| 262 | 
            +
              {
         | 
| 263 | 
            +
                printf("ERROR: DB ist NULL! ");
         | 
| 264 | 
            +
                return NULL;
         | 
| 265 | 
            +
              }
         | 
| 266 | 
            +
              
         | 
| 267 | 
            +
              if(db->ranges_count == 0)
         | 
| 268 | 
            +
              {
         | 
| 269 | 
            +
                printf("ERROR: DB has no Ranges Data. Can not search!\n");
         | 
| 270 | 
            +
                return NULL;
         | 
| 271 | 
            +
              }
         | 
| 272 | 
            +
                
         | 
| 273 | 
            +
              search->from = ip_to_int(ip);
         | 
| 274 | 
            +
              search->to=0;
         | 
| 275 | 
            +
              search->city_index = 0;
         | 
| 276 | 
            +
              if(DEBUG)
         | 
| 277 | 
            +
                printf("Searching for: ip=%s, ipnum=%lu \n", ip, search->from);
         | 
| 278 | 
            +
              // result = (IpRange*) bsearch(search, db->ranges, db->ranges_count-2, sizeof(IpRange), compare_ranges);    
         | 
| 279 | 
            +
              res = bsearch(search, db->ranges, db->ranges_count, sizeof(IpRange), compare_ranges);
         | 
| 280 | 
            +
              if(search != NULL)
         | 
| 281 | 
            +
                free(search);
         | 
| 282 | 
            +
                
         | 
| 283 | 
            +
              if(res == NULL)
         | 
| 284 | 
            +
              { 
         | 
| 285 | 
            +
                if(DEBUG)
         | 
| 286 | 
            +
                printf("ERROR: Could not find the IP: %s! THIS SHOULD NOT HAPPEN!\n", ip);
         | 
| 287 | 
            +
                return NULL;
         | 
| 288 | 
            +
              }else{
         | 
| 289 | 
            +
                result = (IpRange*) res;
         | 
| 290 | 
            +
                if(DEBUG){
         | 
| 291 | 
            +
                  printf("Found Range: \t");    
         | 
| 292 | 
            +
                  print_range(result);  
         | 
| 293 | 
            +
                }
         | 
| 294 | 
            +
              }
         | 
| 295 | 
            +
              
         | 
| 296 | 
            +
              if(db->cities_count == 0)
         | 
| 297 | 
            +
              {
         | 
| 298 | 
            +
                if(DEBUG)
         | 
| 299 | 
            +
                  printf("ERROR: DB has no City Data. Can not search!\n");
         | 
| 300 | 
            +
                return NULL;
         | 
| 301 | 
            +
              }
         | 
| 302 | 
            +
              
         | 
| 303 | 
            +
              
         | 
| 304 | 
            +
              if(result->city_index >0 && result->city_index < db->cities_count)
         | 
| 305 | 
            +
              {
         | 
| 306 | 
            +
                // address the city directly via the array-idx
         | 
| 307 | 
            +
                return &(db->cities[result->city_index]);
         | 
| 308 | 
            +
              } else {
         | 
| 309 | 
            +
                if(DEBUG)
         | 
| 310 | 
            +
                  printf("ERROR: Could not find city with index: %i - THIS SHOULD NOT HAPPEN!\n", result->city_index);
         | 
| 311 | 
            +
                return NULL; 
         | 
| 312 | 
            +
              }
         | 
| 313 | 
            +
            }
         | 
| 314 | 
            +
             | 
| 315 | 
            +
             | 
| 316 | 
            +
            // read ip-ranges from csv file, of format:
         | 
| 317 | 
            +
            // from_ip|to_ip|city_code
         | 
| 318 | 
            +
            void 
         | 
| 319 | 
            +
            read_ranges_csv(IPDB * db){  
         | 
| 320 | 
            +
              struct timeval tim;
         | 
| 321 | 
            +
              double t1 = get_time(&tim);
         | 
| 322 | 
            +
             | 
| 323 | 
            +
              db->ranges = malloc(sizeof(IpRange) * db->max_ranges_count);
         | 
| 324 | 
            +
              
         | 
| 325 | 
            +
              if(DEBUG)
         | 
| 326 | 
            +
                printf("Parsing RANGES-CSV-file: %s\n", db->ranges_csv_file);
         | 
| 327 | 
            +
              FILE * f = fopen(db->ranges_csv_file, "rt");
         | 
| 328 | 
            +
              if(f == NULL)
         | 
| 329 | 
            +
              {
         | 
| 330 | 
            +
                if(DEBUG)
         | 
| 331 | 
            +
                  printf("Could not open the CSV-file: %s", db->ranges_csv_file);
         | 
| 332 | 
            +
                return;
         | 
| 333 | 
            +
              }
         | 
| 334 | 
            +
              char line[256];
         | 
| 335 | 
            +
              char* from = NULL;
         | 
| 336 | 
            +
              char* to = NULL;
         | 
| 337 | 
            +
              char* city_code = NULL;
         | 
| 338 | 
            +
              int invalid_cities_count = 0;
         | 
| 339 | 
            +
              int city_index;
         | 
| 340 | 
            +
              
         | 
| 341 | 
            +
              IpRange* entry;
         | 
| 342 | 
            +
              db->ranges_count = 0;
         | 
| 343 | 
            +
              while (fgets(line,sizeof(line),f) && db->ranges_count < db->max_ranges_count){
         | 
| 344 | 
            +
                if(DEBUG && db->ranges_count % 1000000 == 0)
         | 
| 345 | 
            +
                  printf("Worked lines: %i\n", db->ranges_count);
         | 
| 346 | 
            +
             | 
| 347 | 
            +
                from =      strtok(line, RANGES_DELIM);
         | 
| 348 | 
            +
                to =        strtok(NULL, RANGES_DELIM);
         | 
| 349 | 
            +
                city_code = strtok(NULL, RANGES_DELIM);
         | 
| 350 | 
            +
                city_index = city_index_by_code(db, atoi(city_code));
         | 
| 351 | 
            +
                if(city_index < 0)
         | 
| 352 | 
            +
                { 
         | 
| 353 | 
            +
                  if(DEBUG)
         | 
| 354 | 
            +
                    printf("Could not find city for code: %i", atoi(city_code));
         | 
| 355 | 
            +
                  invalid_cities_count ++;
         | 
| 356 | 
            +
                  continue;
         | 
| 357 | 
            +
                }else{
         | 
| 358 | 
            +
                  entry = &(db->ranges[db->ranges_count]);
         | 
| 359 | 
            +
                
         | 
| 360 | 
            +
                  entry->from = ip_to_int(from);
         | 
| 361 | 
            +
                  entry->to = ip_to_int(to);
         | 
| 362 | 
            +
                  // entry->city_code = atoi(city_code);
         | 
| 363 | 
            +
                
         | 
| 364 | 
            +
                  entry->city_index = city_index;
         | 
| 365 | 
            +
                  // printf("Line: %s", line);
         | 
| 366 | 
            +
                  // printf("from: %u,to: %u, city_code:%i \n",entry->from,entry->to,entry->city_code);
         | 
| 367 | 
            +
                  // db->ranges[i] = *entry;
         | 
| 368 | 
            +
                  // printf("working record nr: %li\n", db->ranges_count);
         | 
| 369 | 
            +
                  db->ranges_count++;
         | 
| 370 | 
            +
                }
         | 
| 371 | 
            +
              } 
         | 
| 372 | 
            +
              if(invalid_cities_count)
         | 
| 373 | 
            +
              {
         | 
| 374 | 
            +
                printf("Found invalid cities: %i", invalid_cities_count);
         | 
| 375 | 
            +
              }
         | 
| 376 | 
            +
              printf("\n Parsing of %i records needed %.6lf seconds\n", db->ranges_count, get_time(&tim)-t1);  
         | 
| 377 | 
            +
            }
         | 
| 378 | 
            +
             | 
| 379 | 
            +
             | 
| 380 | 
            +
             | 
| 381 | 
            +
            //translate country iso3 to iso2
         | 
| 382 | 
            +
            char * 
         | 
| 383 | 
            +
            iso2_code(char* iso3){
         | 
| 384 | 
            +
              int i = 0;
         | 
| 385 | 
            +
              for( i = 0; i < num_countries; i++)
         | 
| 386 | 
            +
              {
         | 
| 387 | 
            +
                // printf("Trying cmp of %s and %s...", iso3, country_iso3_codes[i]);
         | 
| 388 | 
            +
                if(  strcmp(country_iso3_codes[i],iso3)==0)
         | 
| 389 | 
            +
                {
         | 
| 390 | 
            +
                  return (char*) country_iso2_codes[i];
         | 
| 391 | 
            +
                }
         | 
| 392 | 
            +
              }
         | 
| 393 | 
            +
              // printf("Could not find iso2 code for iso3: %s, using: '%s' \n", iso3, country_iso2_codes[0]);
         | 
| 394 | 
            +
              return (char*) country_iso2_codes[0];
         | 
| 395 | 
            +
            }
         | 
| 396 | 
            +
             | 
| 397 | 
            +
            //read city-data from csv-file of format:
         | 
| 398 | 
            +
            // COUNTRY,REGION,CITY-NAME,METRO-CODE,CITY-CODE,LATITUDE,LONGITUDE
         | 
| 399 | 
            +
            void
         | 
| 400 | 
            +
            read_cities_csv(IPDB * db){
         | 
| 401 | 
            +
              struct timeval tim;
         | 
| 402 | 
            +
              double t1 = get_time(&tim);
         | 
| 403 | 
            +
             | 
| 404 | 
            +
              db->cities_count = 0;
         | 
| 405 | 
            +
              db->cities = malloc(sizeof(City) * db->max_cities_count);
         | 
| 406 | 
            +
              
         | 
| 407 | 
            +
              if(DEBUG)
         | 
| 408 | 
            +
                printf("Parsing Cities-CSV-file: %s\n", db->cities_csv_file);
         | 
| 409 | 
            +
              FILE * f = fopen(db->cities_csv_file, "rt");
         | 
| 410 | 
            +
              if(f == NULL)
         | 
| 411 | 
            +
              {
         | 
| 412 | 
            +
                if(DEBUG)
         | 
| 413 | 
            +
                  printf("Could not open the Cities-CSV-file: %s", db->cities_csv_file);
         | 
| 414 | 
            +
                return;
         | 
| 415 | 
            +
              }
         | 
| 416 | 
            +
              char line[256];
         | 
| 417 | 
            +
              char  *country, *region, *name,*metro_code,*city_code,*lat,*lng ;
         | 
| 418 | 
            +
              int i = 0;
         | 
| 419 | 
            +
              City* entry;
         | 
| 420 | 
            +
             | 
| 421 | 
            +
              while (fgets(line,sizeof(line),f) && db->cities_count < db->max_cities_count){
         | 
| 422 | 
            +
                i++;
         | 
| 423 | 
            +
                if(i == 1)
         | 
| 424 | 
            +
                  continue;//skip the header
         | 
| 425 | 
            +
             | 
| 426 | 
            +
                if(DEBUG && i % 1000000 == 0)
         | 
| 427 | 
            +
                {
         | 
| 428 | 
            +
                  printf("Worked lines: %i\n", i);
         | 
| 429 | 
            +
                }
         | 
| 430 | 
            +
               // printf("Line: %s", line);
         | 
| 431 | 
            +
               // COUNTRY,REGION,CITY-NAME,METRO-CODE,CITY-CODE,LATITUDE,LONGITUDE    
         | 
| 432 | 
            +
                country =    strtok(line, CITIES_DELIM);
         | 
| 433 | 
            +
                region =     strtok(NULL, CITIES_DELIM);
         | 
| 434 | 
            +
                name =       strtok(NULL, CITIES_DELIM);
         | 
| 435 | 
            +
                metro_code = strtok(NULL, CITIES_DELIM);    
         | 
| 436 | 
            +
                city_code =  strtok(NULL, CITIES_DELIM);
         | 
| 437 | 
            +
                lat =        strtok(NULL, CITIES_DELIM);
         | 
| 438 | 
            +
                lng =        strtok(NULL, CITIES_DELIM);    
         | 
| 439 | 
            +
                
         | 
| 440 | 
            +
                entry = &(db->cities[db->cities_count]);
         | 
| 441 | 
            +
                
         | 
| 442 | 
            +
                strncpy(entry->country_iso3, country, strlen(country));
         | 
| 443 | 
            +
             | 
| 444 | 
            +
                // entry->country_iso2 = iso2_code(entry->country_iso3);    
         | 
| 445 | 
            +
                strncpy(entry->country_iso2, iso2_code(country), 2);
         | 
| 446 | 
            +
                strncpy(entry->name, name, strlen(name));
         | 
| 447 | 
            +
                    
         | 
| 448 | 
            +
                entry->city_code =    atoi(city_code);
         | 
| 449 | 
            +
                entry->lat =          atof(lat);
         | 
| 450 | 
            +
                entry->lng =          atof(lng);
         | 
| 451 | 
            +
                db->cities_count++;
         | 
| 452 | 
            +
              }
         | 
| 453 | 
            +
              if(DEBUG)
         | 
| 454 | 
            +
                printf("\n Parsing of %i records needed %.6lf seconds\n", db->cities_count, get_time(&tim)-t1);
         | 
| 455 | 
            +
            }
         | 
| 456 | 
            +
             | 
| 457 | 
            +
             | 
| 458 | 
            +
             | 
| 459 | 
            +
            /**
         | 
| 460 | 
            +
            cache-file is an exact binary copy of the ranges+cities-arrays from memory,
         | 
| 461 | 
            +
            the layout goes like this:
         | 
| 462 | 
            +
              db->cities_count [4 Bytes]
         | 
| 463 | 
            +
              db->ranges_count [4 Bytes]
         | 
| 464 | 
            +
             | 
| 465 | 
            +
              db->cities [sizeof(City)=24 x db->ranges_count Bytes]
         | 
| 466 | 
            +
              db->ranges [sizeof(IpRange)=24 x db->ranges_count Bytes]
         | 
| 467 | 
            +
            */
         | 
| 468 | 
            +
            void  
         | 
| 469 | 
            +
            write_cache_file(IPDB * db){
         | 
| 470 | 
            +
              struct timeval tim;
         | 
| 471 | 
            +
              double t1 = get_time(&tim);
         | 
| 472 | 
            +
              int objects_written;
         | 
| 473 | 
            +
              
         | 
| 474 | 
            +
              FILE * f;
         | 
| 475 | 
            +
              f = fopen(db->cache_file_name, "w");
         | 
| 476 | 
            +
              if(f==NULL){
         | 
| 477 | 
            +
                if(DEBUG)
         | 
| 478 | 
            +
                  printf("Could not open Cache-File: %s", db->cache_file_name);
         | 
| 479 | 
            +
                return;
         | 
| 480 | 
            +
              }
         | 
| 481 | 
            +
              if(DEBUG){
         | 
| 482 | 
            +
                printf("Dumping %i records to cache-file: %s\n\n", db->ranges_count, db->cache_file_name);
         | 
| 483 | 
            +
              
         | 
| 484 | 
            +
                //write the record length at file header
         | 
| 485 | 
            +
                printf("Writing DB-Header of length: %li\n",sizeof(db->ranges_count));
         | 
| 486 | 
            +
              
         | 
| 487 | 
            +
                printf("RecordLength: %li\n",sizeof(IpRange));  
         | 
| 488 | 
            +
                printf("FieldLength: %li\n",sizeof(db->ranges[0].from));    
         | 
| 489 | 
            +
              }
         | 
| 490 | 
            +
              //write the header: i.e.: numbers of records
         | 
| 491 | 
            +
              fwrite(&(db->cities_count), sizeof(db->cities_count),1,f);  
         | 
| 492 | 
            +
              fwrite(&(db->ranges_count), sizeof(db->ranges_count),1,f);
         | 
| 493 | 
            +
              
         | 
| 494 | 
            +
              if(DEBUG)
         | 
| 495 | 
            +
                printf("Writing Contents with %i cities, a %li bytes each, should = %li \n", db->cities_count, sizeof(City), db->cities_count * sizeof(City));  
         | 
| 496 | 
            +
              //write the actual data: all the ranges-array-buffer:
         | 
| 497 | 
            +
              objects_written = fwrite(db->cities, sizeof(City), db->cities_count, f);
         | 
| 498 | 
            +
              if(DEBUG)
         | 
| 499 | 
            +
                printf("Writing Contents with %i ranges, a %li bytes each, should = %li \n", db->ranges_count, sizeof(IpRange), db->ranges_count * sizeof(IpRange));  
         | 
| 500 | 
            +
              //write the actual data: all the ranges-array-buffer:
         | 
| 501 | 
            +
              objects_written += fwrite(db->ranges, sizeof(IpRange), db->ranges_count, f);
         | 
| 502 | 
            +
              
         | 
| 503 | 
            +
             | 
| 504 | 
            +
              fclose(f);
         | 
| 505 | 
            +
              if(DEBUG)  
         | 
| 506 | 
            +
                printf("\n Writing CacheFile of %i objects needed %.6lf seconds\n", objects_written, get_time(&tim)-t1);  
         | 
| 507 | 
            +
            }
         | 
| 508 | 
            +
             | 
| 509 | 
            +
            int 
         | 
| 510 | 
            +
            read_cache_file(IPDB * db){ 
         | 
| 511 | 
            +
              struct timeval tim;
         | 
| 512 | 
            +
              double t1 = get_time(&tim);  
         | 
| 513 | 
            +
              FILE * f;
         | 
| 514 | 
            +
              f = fopen(db->cache_file_name, "r");
         | 
| 515 | 
            +
              if(f==NULL){
         | 
| 516 | 
            +
                if(DEBUG)
         | 
| 517 | 
            +
                  printf("Could not open Cache-File: %s", db->cache_file_name);
         | 
| 518 | 
            +
                return 0;
         | 
| 519 | 
            +
              }
         | 
| 520 | 
            +
              int cities_header_read = fread(&(db->cities_count), sizeof(db->cities_count),1,f);
         | 
| 521 | 
            +
              int ranges_header_read = fread(&(db->ranges_count), sizeof(db->ranges_count),1,f);
         | 
| 522 | 
            +
             | 
| 523 | 
            +
              
         | 
| 524 | 
            +
              if(cities_header_read == 0 || ranges_header_read == 0 || db->cities_count == 0 || db->ranges_count ==0 )
         | 
| 525 | 
            +
              {
         | 
| 526 | 
            +
                printf("Could not read Cities-Header from Cache-File: %s", db->cache_file_name);
         | 
| 527 | 
            +
                return 0;
         | 
| 528 | 
            +
              }
         | 
| 529 | 
            +
              if(DEBUG)  
         | 
| 530 | 
            +
                printf("Reading DB-Header from Cache-File: %s, with %i cities and %i ranges\n",db->cache_file_name, db->cities_count, db->ranges_count);  
         | 
| 531 | 
            +
             | 
| 532 | 
            +
              int objects_read = 0;
         | 
| 533 | 
            +
              if(DEBUG)
         | 
| 534 | 
            +
                printf("Allocating: %lu for cities-array \n", sizeof(City)*(db->cities_count));
         | 
| 535 | 
            +
              db->cities = malloc(sizeof(City) * db->cities_count);
         | 
| 536 | 
            +
              objects_read += fread(db->cities, sizeof(City),db->cities_count,f);
         | 
| 537 | 
            +
              if(DEBUG)
         | 
| 538 | 
            +
                printf("Allocating: %lu for ranges-array \n", sizeof(IpRange)*(db->ranges_count));
         | 
| 539 | 
            +
              db->ranges = malloc(sizeof(IpRange) * db->ranges_count);
         | 
| 540 | 
            +
              objects_read += fread(db->ranges, sizeof(IpRange),db->ranges_count,f);
         | 
| 541 | 
            +
              
         | 
| 542 | 
            +
             | 
| 543 | 
            +
              fclose(f);
         | 
| 544 | 
            +
              if(DEBUG)  
         | 
| 545 | 
            +
                printf("Reading cacheFile of %i objects needed %.6lf seconds\n", objects_read, get_time(&tim)-t1);    
         | 
| 546 | 
            +
              return objects_read;
         | 
| 547 | 
            +
            }
         | 
| 548 | 
            +
             | 
| 549 | 
            +
            void 
         | 
| 550 | 
            +
            benchmark_search(IPDB * db,int count){
         | 
| 551 | 
            +
              printf("(Naiv) benchmark of the City-Search-Function with %i counts \n", count);
         | 
| 552 | 
            +
              struct timeval tim;  
         | 
| 553 | 
            +
              double t1 = get_time(&tim);
         | 
| 554 | 
            +
              int i;
         | 
| 555 | 
            +
              City * city;
         | 
| 556 | 
            +
             | 
| 557 | 
            +
              for(i=0;i<count; i++){
         | 
| 558 | 
            +
                 city = city_by_ip(db, "278.50.47.0");
         | 
| 559 | 
            +
              }
         | 
| 560 | 
            +
              double delta = get_time(&tim)-t1;
         | 
| 561 | 
            +
              
         | 
| 562 | 
            +
              printf("\n\nSearch: %.6lf seconds elapsed, i.e. %.6lf Ops/Second \n", delta, count / delta);  
         | 
| 563 | 
            +
            }
         | 
| 564 | 
            +
             | 
| 565 | 
            +
            IPDB * init_db(char * cities_csv_file, char * ranges_csv_file, char * cache_file_name){
         | 
| 566 | 
            +
              IPDB *db;
         | 
| 567 | 
            +
              db = (IPDB*)malloc(sizeof(IPDB));
         | 
| 568 | 
            +
              if (db == NULL) //no memory left
         | 
| 569 | 
            +
                return NULL;
         | 
| 570 | 
            +
              db->cities = NULL;
         | 
| 571 | 
            +
              db->ranges = NULL;
         | 
| 572 | 
            +
              db->cache_file_name = cache_file_name;
         | 
| 573 | 
            +
             | 
| 574 | 
            +
              db->cities_csv_file = cities_csv_file;
         | 
| 575 | 
            +
              db->max_cities_count = MAX_CITIES_COUNT;
         | 
| 576 | 
            +
              db->ranges_csv_file = ranges_csv_file;
         | 
| 577 | 
            +
              db->max_ranges_count = MAX_RANGES_COUNT;
         | 
| 578 | 
            +
                
         | 
| 579 | 
            +
             | 
| 580 | 
            +
              if(USE_CACHE && read_cache_file(db) > 0){
         | 
| 581 | 
            +
                if(DEBUG)
         | 
| 582 | 
            +
                  printf("Loaded DB from Cache-File with %i records \n", db->ranges_count);
         | 
| 583 | 
            +
              }else{
         | 
| 584 | 
            +
                if(DEBUG)
         | 
| 585 | 
            +
                  printf("Initializing IPDB from CSV-file: %s \n", db->ranges_csv_file);    
         | 
| 586 | 
            +
                read_cities_csv(db);
         | 
| 587 | 
            +
                // print_cities(db);
         | 
| 588 | 
            +
                if(db->cities_count == 0)
         | 
| 589 | 
            +
                {
         | 
| 590 | 
            +
                  return NULL;
         | 
| 591 | 
            +
                }
         | 
| 592 | 
            +
                sort_cities(db);
         | 
| 593 | 
            +
                read_ranges_csv(db);
         | 
| 594 | 
            +
                // //TODO: sort ranges
         | 
| 595 | 
            +
                if(db!=NULL && db->ranges_count > 0 && USE_CACHE)
         | 
| 596 | 
            +
                {
         | 
| 597 | 
            +
                  if(DEBUG)
         | 
| 598 | 
            +
                    printf("Got %i records from CSV-file, writing to cache...\n", db->ranges_count);    
         | 
| 599 | 
            +
                  write_cache_file(db);
         | 
| 600 | 
            +
                }
         | 
| 601 | 
            +
              }
         | 
| 602 | 
            +
              return db;  
         | 
| 603 | 
            +
            }
         | 
| 604 | 
            +
             | 
    
        data/ext/ipdb.h
    ADDED
    
    | @@ -0,0 +1,69 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            #ifdef INT_2_BYTES
         | 
| 3 | 
            +
            typedef char int8;
         | 
| 4 | 
            +
            typedef int int16;
         | 
| 5 | 
            +
            typedef unsigned int uint16;
         | 
| 6 | 
            +
            typedef long int32;
         | 
| 7 | 
            +
            #else
         | 
| 8 | 
            +
            typedef char int8;
         | 
| 9 | 
            +
            typedef short int16;
         | 
| 10 | 
            +
            typedef unsigned short uint16;
         | 
| 11 | 
            +
            typedef int int32;
         | 
| 12 | 
            +
            #endif
         | 
| 13 | 
            +
             | 
| 14 | 
            +
             | 
| 15 | 
            +
            #define RANGES_DELIM "|"
         | 
| 16 | 
            +
            #define CITIES_DELIM ","
         | 
| 17 | 
            +
            #define MAX_CITIES_COUNT 100000 //Usually we have about 50 000 Cities
         | 
| 18 | 
            +
            #define MAX_RANGES_COUNT 10000000 //Usually we have about 6 Mio IP-Ranges
         | 
| 19 | 
            +
             | 
| 20 | 
            +
             | 
| 21 | 
            +
            #define USE_CACHE 1
         | 
| 22 | 
            +
            #define DEBUG 0
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            typedef struct{
         | 
| 25 | 
            +
              unsigned long from;
         | 
| 26 | 
            +
              unsigned long to;
         | 
| 27 | 
            +
              // uint16 city_code; //city codes are not larger than 2**16 = 65536
         | 
| 28 | 
            +
              uint16 city_index; //index of the city in the cities-array
         | 
| 29 | 
            +
            } IpRange;
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            typedef struct{
         | 
| 32 | 
            +
              uint16 city_code; //city codes are not larger than 2**16 = 65536
         | 
| 33 | 
            +
              char name[32];
         | 
| 34 | 
            +
              double lat;
         | 
| 35 | 
            +
              double lng;
         | 
| 36 | 
            +
              
         | 
| 37 | 
            +
              char country_iso3[4];
         | 
| 38 | 
            +
              char country_iso2[3];  
         | 
| 39 | 
            +
            } City;
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            typedef struct{
         | 
| 42 | 
            +
              char *ranges_csv_file; //the CSV-file with ip-ranges-to-city-code-mappings
         | 
| 43 | 
            +
              unsigned int max_ranges_count;
         | 
| 44 | 
            +
              unsigned int ranges_count;
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              char *cities_csv_file;
         | 
| 47 | 
            +
              unsigned int cities_count;  
         | 
| 48 | 
            +
              unsigned int max_cities_count;
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              
         | 
| 51 | 
            +
              char *cache_file_name; // a binary file to store the whole db.....
         | 
| 52 | 
            +
              IpRange * ranges;
         | 
| 53 | 
            +
              City * cities;
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            } IPDB;
         | 
| 56 | 
            +
             | 
| 57 | 
            +
             | 
| 58 | 
            +
            // "publicly" visible functions
         | 
| 59 | 
            +
            IPDB * 
         | 
| 60 | 
            +
            init_db(char * cities_csv_file, char * ranges_csv_file, char * cache_file_name);
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            City * 
         | 
| 63 | 
            +
            city_by_ip(IPDB *db, char *ip);
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            void 
         | 
| 66 | 
            +
            print_city(const City * e);
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            void 
         | 
| 69 | 
            +
            benchmark_search(IPDB * db,int count);
         | 
    
        data/ext/test.c
    ADDED
    
    | @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            #include "ipdb.h"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #include <search.h>
         | 
| 4 | 
            +
            #include <stdio.h>
         | 
| 5 | 
            +
            #include <string.h>
         | 
| 6 | 
            +
            #include <stdlib.h>
         | 
| 7 | 
            +
            #include <sys/time.h>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            int main() {
         | 
| 12 | 
            +
              IPDB * db = init_db("data/cities.csv", "data/ip_ranges.csv", "data/ipdb.cache");
         | 
| 13 | 
            +
              // IPDB * db = init_db(NULL, NULL, NULL);  
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              // City * city;
         | 
| 17 | 
            +
              // 
         | 
| 18 | 
            +
              // // city = city_by_ip(db, "1.16.0.0");  
         | 
| 19 | 
            +
              // int i;
         | 
| 20 | 
            +
              int count = 10000000;
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
              benchmark_search(db, count);
         | 
| 23 | 
            +
              
         | 
| 24 | 
            +
              // for(i = 0; i < count; ++i)
         | 
| 25 | 
            +
              // {
         | 
| 26 | 
            +
              //   if(i % 100000 == 0)
         | 
| 27 | 
            +
              //     printf("Working: i= %i \n", i);
         | 
| 28 | 
            +
              //     
         | 
| 29 | 
            +
              //   city = city_by_ip(db, "91.44.93.35");
         | 
| 30 | 
            +
              // }
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
| 34 | 
            +
             | 
| 35 | 
            +
              
         | 
| 36 | 
            +
             //  
         | 
| 37 | 
            +
              int * response;
         | 
| 38 | 
            +
              scanf("%i",response);
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              return 0;
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            }
         | 
    
        data/geoipdb.gemspec
    ADDED
    
    | @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            # Generated by jeweler
         | 
| 2 | 
            +
            # DO NOT EDIT THIS FILE DIRECTLY
         | 
| 3 | 
            +
            # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
         | 
| 4 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |s|
         | 
| 7 | 
            +
              s.name = %q{geoipdb}
         | 
| 8 | 
            +
              s.version = "0.1.4"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 | 
            +
              s.authors = ["Eugen Martin"]
         | 
| 12 | 
            +
              s.date = %q{2011-01-13}
         | 
| 13 | 
            +
              s.description = %q{Returns a GeoLocation to a given IP. Reads Data from CSV-Files and uses internal binary caching.}
         | 
| 14 | 
            +
              s.email = %q{eugeniusmartinus@googlemail.com}
         | 
| 15 | 
            +
              s.extensions = ["ext/extconf.rb"]
         | 
| 16 | 
            +
              s.extra_rdoc_files = [
         | 
| 17 | 
            +
                "LICENSE.txt",
         | 
| 18 | 
            +
                "README.markdown"
         | 
| 19 | 
            +
              ]
         | 
| 20 | 
            +
              s.files = [
         | 
| 21 | 
            +
                ".document",
         | 
| 22 | 
            +
                ".rspec",
         | 
| 23 | 
            +
                "Gemfile",
         | 
| 24 | 
            +
                "LICENSE.txt",
         | 
| 25 | 
            +
                "README.markdown",
         | 
| 26 | 
            +
                "Rakefile",
         | 
| 27 | 
            +
                "VERSION",
         | 
| 28 | 
            +
                "ext/build.sh",
         | 
| 29 | 
            +
                "ext/extconf.rb",
         | 
| 30 | 
            +
                "ext/geoipdb.c",
         | 
| 31 | 
            +
                "ext/ipdb.c",
         | 
| 32 | 
            +
                "ext/ipdb.h",
         | 
| 33 | 
            +
                "ext/test.c",
         | 
| 34 | 
            +
                "geoipdb.gemspec",
         | 
| 35 | 
            +
                "lib/geoipdb.rb",
         | 
| 36 | 
            +
                "spec/geoipdb_spec.rb",
         | 
| 37 | 
            +
                "spec/spec_helper.rb"
         | 
| 38 | 
            +
              ]
         | 
| 39 | 
            +
              s.homepage = %q{http://github.com/olgen/geoipdb}
         | 
| 40 | 
            +
              s.licenses = ["MIT"]
         | 
| 41 | 
            +
              s.require_paths = ["ext"]
         | 
| 42 | 
            +
              s.rubygems_version = %q{1.3.7}
         | 
| 43 | 
            +
              s.summary = %q{Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.}
         | 
| 44 | 
            +
              s.test_files = [
         | 
| 45 | 
            +
                "spec/geoipdb_spec.rb",
         | 
| 46 | 
            +
                "spec/spec_helper.rb"
         | 
| 47 | 
            +
              ]
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              if s.respond_to? :specification_version then
         | 
| 50 | 
            +
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         | 
| 51 | 
            +
                s.specification_version = 3
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
         | 
| 54 | 
            +
                  s.add_development_dependency(%q<rspec>, ["~> 2.1.0"])
         | 
| 55 | 
            +
                  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
         | 
| 56 | 
            +
                  s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
         | 
| 57 | 
            +
                  s.add_development_dependency(%q<rcov>, [">= 0"])
         | 
| 58 | 
            +
                else
         | 
| 59 | 
            +
                  s.add_dependency(%q<rspec>, ["~> 2.1.0"])
         | 
| 60 | 
            +
                  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
         | 
| 61 | 
            +
                  s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
         | 
| 62 | 
            +
                  s.add_dependency(%q<rcov>, [">= 0"])
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              else
         | 
| 65 | 
            +
                s.add_dependency(%q<rspec>, ["~> 2.1.0"])
         | 
| 66 | 
            +
                s.add_dependency(%q<bundler>, ["~> 1.0.0"])
         | 
| 67 | 
            +
                s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
         | 
| 68 | 
            +
                s.add_dependency(%q<rcov>, [">= 0"])
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
            end
         | 
| 71 | 
            +
             | 
    
        data/lib/geoipdb.rb
    ADDED
    
    | 
            File without changes
         | 
| @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            COUNTRY,REGION,CITY-NAME,METRO-CODE,CITY-CODE,LATITUDE,LONGITUDE
         | 
| 2 | 
            +
            ***,***,?,0,7,0,0
         | 
| 3 | 
            +
            afg,?,?,0,1,33,1
         | 
| 4 | 
            +
            afg,no region,herat,-1,2,34.3452,62.
         | 
| 5 | 
            +
            afg,no region,kabul,-1,3,34.5167,69.1833
         | 
| 6 | 
            +
            afg,no region,kandahar,-1,4,31.6111,65.702
         | 
| 7 | 
            +
            afg,no region,mazar-e sharif,-1,5,36.7041,67.1096
         | 
| @@ -0,0 +1,8 @@ | |
| 1 | 
            +
            COUNTRY,REGION,CITY-NAME,METRO-CODE,CITY-CODE,LATITUDE,LONGITUDE
         | 
| 2 | 
            +
            ***,***,?,0,7,0,0
         | 
| 3 | 
            +
            afg,?,?,0,1,33,1
         | 
| 4 | 
            +
            afg,no region,herat,-1,2,34.3452,62.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            afg,no , , , , region,kabul,-1,3,34.5167,69.1833
         | 
| 7 | 
            +
            afg,no region,, , kandahar,-1,4,31.6111,65.702
         | 
| 8 | 
            +
            afg,no region,maza , ,r-e sharif,-1,5,36.7041,67.1096
         | 
| @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            start_ip|end_ip|field 13|
         | 
| 2 | 
            +
            0.0.0.0|0.0.0.255|0|
         | 
| 3 | 
            +
            0.0.1.0|0.255.255.255|1|
         | 
| 4 | 
            +
            1.0.0.0|1.0.0.255|2|
         | 
| 5 | 
            +
            1.0.1.0|1.1.0.255|3|
         | 
| 6 | 
            +
            1.1.1.0|1.1.1.255|4|
         | 
| 7 | 
            +
            1.1.2.0|1.2.2.255|5|
         | 
| 8 | 
            +
            1.2.3.0|1.2.3.255|5|
         | 
| 9 | 
            +
            1.2.4.0|1.3.255.255|2|
         | 
| 10 | 
            +
            1.4.0.0|1.4.0.255|5|
         | 
| 11 | 
            +
            1.4.1.0|1.8.255.255|3|
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            start_ip|end_ip|field 13|
         | 
| 5 | 
            +
            0.0.0.0|0.0.0.255|0|
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            0.0.1.0|0.255.255.255|1|
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            1.0.0.0|1.0.0.255|2|
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            1.0.1.0|1.1.0.255|3|
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            asfdasdf asdf asfasdfasdf§$%&/
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            1, | | 7 |.1.1.0|1.1.1.255|4|
         | 
| 16 | 
            +
            1.1.2.0|1.2.2.255|5|
         | 
| 17 | 
            +
            1.2.3.0|1.2.3.255|5|
         | 
| 18 | 
            +
            1.2.4.0|1.3.255.255|2|
         | 
| 19 | 
            +
            1.4.0.0|1.4.0.255|5|
         | 
| 20 | 
            +
            1.4.1.0|1.8.255.255|3|
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            require File.expand_path(File.dirname(__FILE__)+'/spec_helper')
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe "Geoipdb" do
         | 
| 5 | 
            +
              def init_db
         | 
| 6 | 
            +
                @db = GeoIpDb.init './sample_data/cities.csv', './sample_data/ip_ranges.csv', @cache_file
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              before :each do
         | 
| 10 | 
            +
                @cache_file = 'sample_data/ipdb.cache'
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
              it "should init correctly with sample data and create the cache-file" do
         | 
| 14 | 
            +
                init_db
         | 
| 15 | 
            +
                @db.should_not be_nil
         | 
| 16 | 
            +
                File.exist?(@cache_file).should be_true
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
              it "sould find the sample cities correcty" do 
         | 
| 20 | 
            +
                init_db
         | 
| 21 | 
            +
                #afg,no region,kabul,-1,3,34.5167,69.1833
         | 
| 22 | 
            +
                @db.city_by_ip("1.1.0.254").should == {'city_code'=>3, 'name'=>'kabul', 'country'=>'af', 'lat'=>34.5167, 'lng'=>69.1833}
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
              
         | 
| 25 | 
            +
              it "should not throw an exception fault if data is corrupt" do
         | 
| 26 | 
            +
                @db = GeoIpDb.init './sample_data/cities_corrupt.csv', './sample_data/ip_ranges_corrupt.csv', @cache_file    
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              it "should not init a db object if data files are missing" do
         | 
| 30 | 
            +
                GeoIpDb.init( './sample_data/bla.csv', './sample_data/blubb.csv', @cache_file    ).should be_nil
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              
         | 
| 34 | 
            +
              after :each do
         | 
| 35 | 
            +
                File.unlink @cache_file if File.exist? @cache_file
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'ext'))
         | 
| 2 | 
            +
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         | 
| 3 | 
            +
            require 'rspec'
         | 
| 4 | 
            +
            require 'geoipdb'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # Requires supporting files with custom matchers and macros, etc,
         | 
| 7 | 
            +
            # in ./support/ and its subdirectories.
         | 
| 8 | 
            +
            Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            RSpec.configure do |config|
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: geoipdb
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              hash: 19
         | 
| 5 | 
            +
              prerelease: 
         | 
| 6 | 
            +
              segments: 
         | 
| 7 | 
            +
              - 0
         | 
| 8 | 
            +
              - 1
         | 
| 9 | 
            +
              - 4
         | 
| 10 | 
            +
              version: 0.1.4
         | 
| 11 | 
            +
            platform: ruby
         | 
| 12 | 
            +
            authors: 
         | 
| 13 | 
            +
            - Eugen Martin
         | 
| 14 | 
            +
            autorequire: 
         | 
| 15 | 
            +
            bindir: bin
         | 
| 16 | 
            +
            cert_chain: []
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            date: 2011-01-14 00:00:00 +01:00
         | 
| 19 | 
            +
            default_executable: 
         | 
| 20 | 
            +
            dependencies: 
         | 
| 21 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 22 | 
            +
              type: :development
         | 
| 23 | 
            +
              version_requirements: &id001 !ruby/object:Gem::Requirement 
         | 
| 24 | 
            +
                none: false
         | 
| 25 | 
            +
                requirements: 
         | 
| 26 | 
            +
                - - ~>
         | 
| 27 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 28 | 
            +
                    hash: 11
         | 
| 29 | 
            +
                    segments: 
         | 
| 30 | 
            +
                    - 2
         | 
| 31 | 
            +
                    - 1
         | 
| 32 | 
            +
                    - 0
         | 
| 33 | 
            +
                    version: 2.1.0
         | 
| 34 | 
            +
              requirement: *id001
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              name: rspec
         | 
| 37 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 38 | 
            +
              type: :development
         | 
| 39 | 
            +
              version_requirements: &id002 !ruby/object:Gem::Requirement 
         | 
| 40 | 
            +
                none: false
         | 
| 41 | 
            +
                requirements: 
         | 
| 42 | 
            +
                - - ~>
         | 
| 43 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 44 | 
            +
                    hash: 23
         | 
| 45 | 
            +
                    segments: 
         | 
| 46 | 
            +
                    - 1
         | 
| 47 | 
            +
                    - 0
         | 
| 48 | 
            +
                    - 0
         | 
| 49 | 
            +
                    version: 1.0.0
         | 
| 50 | 
            +
              requirement: *id002
         | 
| 51 | 
            +
              prerelease: false
         | 
| 52 | 
            +
              name: bundler
         | 
| 53 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 54 | 
            +
              type: :development
         | 
| 55 | 
            +
              version_requirements: &id003 !ruby/object:Gem::Requirement 
         | 
| 56 | 
            +
                none: false
         | 
| 57 | 
            +
                requirements: 
         | 
| 58 | 
            +
                - - ~>
         | 
| 59 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 60 | 
            +
                    hash: 1
         | 
| 61 | 
            +
                    segments: 
         | 
| 62 | 
            +
                    - 1
         | 
| 63 | 
            +
                    - 5
         | 
| 64 | 
            +
                    - 1
         | 
| 65 | 
            +
                    version: 1.5.1
         | 
| 66 | 
            +
              requirement: *id003
         | 
| 67 | 
            +
              prerelease: false
         | 
| 68 | 
            +
              name: jeweler
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 70 | 
            +
              type: :development
         | 
| 71 | 
            +
              version_requirements: &id004 !ruby/object:Gem::Requirement 
         | 
| 72 | 
            +
                none: false
         | 
| 73 | 
            +
                requirements: 
         | 
| 74 | 
            +
                - - ">="
         | 
| 75 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 76 | 
            +
                    hash: 3
         | 
| 77 | 
            +
                    segments: 
         | 
| 78 | 
            +
                    - 0
         | 
| 79 | 
            +
                    version: "0"
         | 
| 80 | 
            +
              requirement: *id004
         | 
| 81 | 
            +
              prerelease: false
         | 
| 82 | 
            +
              name: rcov
         | 
| 83 | 
            +
            description: Returns a GeoLocation to a given IP. Reads Data from CSV-Files and uses internal binary caching.
         | 
| 84 | 
            +
            email: eugeniusmartinus@googlemail.com
         | 
| 85 | 
            +
            executables: []
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            extensions: 
         | 
| 88 | 
            +
            - ext/extconf.rb
         | 
| 89 | 
            +
            extra_rdoc_files: 
         | 
| 90 | 
            +
            - LICENSE.txt
         | 
| 91 | 
            +
            - README.markdown
         | 
| 92 | 
            +
            files: 
         | 
| 93 | 
            +
            - .document
         | 
| 94 | 
            +
            - .rspec
         | 
| 95 | 
            +
            - Gemfile
         | 
| 96 | 
            +
            - LICENSE.txt
         | 
| 97 | 
            +
            - README.markdown
         | 
| 98 | 
            +
            - Rakefile
         | 
| 99 | 
            +
            - VERSION
         | 
| 100 | 
            +
            - ext/build.sh
         | 
| 101 | 
            +
            - ext/extconf.rb
         | 
| 102 | 
            +
            - ext/geoipdb.c
         | 
| 103 | 
            +
            - ext/ipdb.c
         | 
| 104 | 
            +
            - ext/ipdb.h
         | 
| 105 | 
            +
            - ext/test.c
         | 
| 106 | 
            +
            - geoipdb.gemspec
         | 
| 107 | 
            +
            - lib/geoipdb.rb
         | 
| 108 | 
            +
            - sample_data/cities.csv
         | 
| 109 | 
            +
            - sample_data/citiess_corrupt.csv
         | 
| 110 | 
            +
            - sample_data/ip_ranges.csv
         | 
| 111 | 
            +
            - sample_data/ip_ranges_corrupt.csv
         | 
| 112 | 
            +
            - spec/geoipdb_spec.rb
         | 
| 113 | 
            +
            - spec/spec_helper.rb
         | 
| 114 | 
            +
            has_rdoc: true
         | 
| 115 | 
            +
            homepage: http://github.com/olgen/geoipdb
         | 
| 116 | 
            +
            licenses: 
         | 
| 117 | 
            +
            - MIT
         | 
| 118 | 
            +
            post_install_message: 
         | 
| 119 | 
            +
            rdoc_options: []
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            require_paths: 
         | 
| 122 | 
            +
            - ext
         | 
| 123 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 124 | 
            +
              none: false
         | 
| 125 | 
            +
              requirements: 
         | 
| 126 | 
            +
              - - ">="
         | 
| 127 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 128 | 
            +
                  hash: 3
         | 
| 129 | 
            +
                  segments: 
         | 
| 130 | 
            +
                  - 0
         | 
| 131 | 
            +
                  version: "0"
         | 
| 132 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 133 | 
            +
              none: false
         | 
| 134 | 
            +
              requirements: 
         | 
| 135 | 
            +
              - - ">="
         | 
| 136 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 137 | 
            +
                  hash: 3
         | 
| 138 | 
            +
                  segments: 
         | 
| 139 | 
            +
                  - 0
         | 
| 140 | 
            +
                  version: "0"
         | 
| 141 | 
            +
            requirements: []
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            rubyforge_project: 
         | 
| 144 | 
            +
            rubygems_version: 1.4.2
         | 
| 145 | 
            +
            signing_key: 
         | 
| 146 | 
            +
            specification_version: 3
         | 
| 147 | 
            +
            summary: Fast (>3 Mio queries/sec!!!) GeoIpDb implementation for Ruby using C-Extensions.
         | 
| 148 | 
            +
            test_files: 
         | 
| 149 | 
            +
            - spec/geoipdb_spec.rb
         | 
| 150 | 
            +
            - spec/spec_helper.rb
         |