extensions/geoip/GeoIP.c
author David Anderson <dvander@alliedmods.net>
Fri Jun 22 17:24:48 2007 +0000 (2007-06-22)
changeset 1002 786f5abf93ea
parent 357 0be2b0acc0e5
permissions -rw-r--r--
fixed a bug where the "keyOnly" parameter to KvGotoNextKey was read backwards
     1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
     2 /* GeoIP.c
     3  *
     4  * Copyright (C) 2006 MaxMind LLC
     5  *
     6  * This library is free software; you can redistribute it and/or
     7  * modify it under the terms of the GNU Lesser General Public
     8  * License as published by the Free Software Foundation; either
     9  * version 2.1 of the License, or (at your option) any later version.
    10  *
    11  * This library is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    14  * Lesser General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU Lesser General Public
    17  * License along with this library; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    19  */
    20 
    21 #define GEOIPDATADIR ""
    22 
    23 #include "GeoIP.h"
    24 
    25 #ifndef _WIN32
    26 #include <netdb.h>
    27 #include <sys/socket.h>
    28 #include <netinet/in.h> /* For ntohl */
    29 #include <arpa/inet.h>
    30 #else
    31 #include <windows.h>
    32 #define snprintf _snprintf
    33 #endif
    34 #include <errno.h>
    35 #include <stdio.h>
    36 #include <stdlib.h>
    37 #include <string.h>
    38 #include <assert.h>
    39 #include <sys/types.h> /* for fstat */
    40 #include <sys/stat.h>	/* for fstat */
    41 
    42 #ifdef HAVE_STDINT_H
    43 #include <stdint.h>     /* For uint32_t */
    44 #endif
    45 
    46 #ifndef        INADDR_NONE
    47 #define        INADDR_NONE     -1
    48 #endif
    49 
    50 #define COUNTRY_BEGIN 16776960
    51 #define STATE_BEGIN_REV0 16700000
    52 #define STATE_BEGIN_REV1 16000000
    53 #define STRUCTURE_INFO_MAX_SIZE 20
    54 #define DATABASE_INFO_MAX_SIZE 100
    55 #define MAX_ORG_RECORD_LENGTH 300
    56 #define US_OFFSET 1
    57 #define CANADA_OFFSET 677
    58 #define WORLD_OFFSET 1353
    59 #define FIPS_RANGE 360
    60 
    61 #define CHECK_ERR(err, msg) { \
    62 		if (err != Z_OK) { \
    63 				fprintf(stderr, "%s error: %d\n", msg, err); \
    64 				exit(1); \
    65 		} \
    66 }
    67 
    68 const char GeoIP_country_code[251][3] = { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
    69 	"AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
    70 	"BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
    71 	"BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
    72 	"CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
    73 	"CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
    74 	"DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
    75 	"FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
    76 	"GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
    77 	"GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
    78 	"IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
    79 	"JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
    80 	"KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
    81 	"LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
    82 	"MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
    83 	"MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
    84 	"NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
    85 	"PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
    86 	"PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
    87 	"SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
    88 	"SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
    89 	"TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
    90 	"TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
    91 	"VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
    92 	"ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE"};
    93 
    94 const char GeoIP_country_code3[251][4] = { "--","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
    95 	"AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
    96 	"BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
    97 	"BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
    98 	"CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
    99 	"CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
   100 	"DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
   101 	"FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
   102 	"GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
   103 	"GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
   104 	"IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
   105 	"JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
   106 	"CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
   107 	"LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
   108 	"MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
   109 	"MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
   110 	"NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
   111 	"PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
   112 	"PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
   113 	"SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
   114 	"SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
   115 	"TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
   116 	"TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
   117 	"VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
   118 	"ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY"};
   119 
   120 const char * GeoIP_country_name[251] = {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
   121 	"Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
   122 	"Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
   123 	"Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
   124 	"Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
   125 	"Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
   126 	"Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
   127 	"Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
   128 	"Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
   129 	"Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
   130 	"Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
   131 	"Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
   132 	"Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
   133 	"Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
   134 	"Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
   135 	"Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
   136 	"Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
   137 	"Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
   138 	"Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
   139 	"Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
   140 	"Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
   141 	"Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
   142 	"Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
   143 	"Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
   144 	"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey"};
   145 
   146 const char GeoIP_country_continent[251][3] = {"--","AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
   147 	"AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
   148 	"AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
   149 	"SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
   150 	"AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
   151 	"SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
   152 	"AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
   153 	"SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
   154 	"AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
   155 	"OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
   156 	"EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
   157 	"AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
   158 	"SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
   159 	"EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
   160 	"AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
   161 	"AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
   162 	"EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
   163 	"OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
   164 	"SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
   165 	"EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
   166 	"SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
   167 	"AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
   168 	"AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
   169 	"SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
   170 	"AF","EU","AF","--","--","--","EU","EU","EU","EU"};
   171 
   172 const char * GeoIPDBDescription[NUM_DB_TYPES] = {NULL, "GeoIP Country Edition", "GeoIP City Edition, Rev 1", "GeoIP Region Edition, Rev 1", "GeoIP ISP Edition", "GeoIP Organization Edition", "GeoIP City Edition, Rev 0", "GeoIP Region Edition, Rev 0","GeoIP Proxy Edition","GeoIP ASNum Edition","GeoIP Netspeed Edition","GeoIP Domain Name Edition"};
   173 
   174 char * custom_directory = NULL;
   175 
   176 void GeoIP_setup_custom_directory (char * dir) {
   177 	custom_directory = dir;
   178 }
   179 
   180 char *_GeoIP_full_path_to(const char *file_name) {
   181 	char *path = malloc(sizeof(char) * 1024);
   182 
   183 	if (custom_directory == NULL){
   184 #ifndef _WIN32
   185 		memset(path, 0, sizeof(char) * 1024);
   186 		snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", GEOIPDATADIR, file_name);
   187 #else
   188 		char buf[MAX_PATH], *p, *q = NULL;
   189 		int len;
   190 		memset(buf, 0, sizeof(buf));
   191 		len = GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf) - 1);
   192 		for (p = buf + len; p > buf; p--)
   193 			if (*p == '\\')
   194 				{
   195 					if (!q)
   196 						q = p;
   197 					else
   198 						*p = '/';
   199 				}
   200 		*q = 0;
   201 		memset(path, 0, sizeof(char) * 1024);
   202 		snprintf(path, sizeof(char) * 1024 - 1, "%s/%s", buf, file_name);
   203 #endif
   204 	} else {
   205 		size_t l = strlen(custom_directory);
   206 		if (custom_directory[l-1] != '/') {
   207 			snprintf(path, sizeof(char) * 1024 - 1, "%s/%s",custom_directory, file_name);
   208 		} else {
   209 			snprintf(path, sizeof(char) * 1024 - 1, "%s%s", custom_directory, file_name);
   210 		}
   211 	}
   212 	return path;
   213 }
   214 
   215 char ** GeoIPDBFileName = NULL;
   216 
   217 void _GeoIP_setup_dbfilename() {
   218 	if (NULL == GeoIPDBFileName) {
   219 		GeoIPDBFileName = malloc(sizeof(char *) * NUM_DB_TYPES);
   220 		memset(GeoIPDBFileName, 0, sizeof(char *) * NUM_DB_TYPES);
   221 
   222 		GeoIPDBFileName[GEOIP_COUNTRY_EDITION]		= _GeoIP_full_path_to("GeoIP.dat");
   223 		GeoIPDBFileName[GEOIP_REGION_EDITION_REV0]	= _GeoIP_full_path_to("GeoIPRegion.dat");
   224 		GeoIPDBFileName[GEOIP_REGION_EDITION_REV1]	= _GeoIP_full_path_to("GeoIPRegion.dat");
   225 		GeoIPDBFileName[GEOIP_CITY_EDITION_REV0]	= _GeoIP_full_path_to("GeoIPCity.dat");
   226 		GeoIPDBFileName[GEOIP_CITY_EDITION_REV1]	= _GeoIP_full_path_to("GeoIPCity.dat");
   227 		GeoIPDBFileName[GEOIP_ISP_EDITION]		= _GeoIP_full_path_to("GeoIPISP.dat");
   228 		GeoIPDBFileName[GEOIP_ORG_EDITION]		= _GeoIP_full_path_to("GeoIPOrg.dat");
   229 		GeoIPDBFileName[GEOIP_PROXY_EDITION]		= _GeoIP_full_path_to("GeoIPProxy.dat");
   230 		GeoIPDBFileName[GEOIP_ASNUM_EDITION]		= _GeoIP_full_path_to("GeoIPASNum.dat");
   231 		GeoIPDBFileName[GEOIP_NETSPEED_EDITION]		= _GeoIP_full_path_to("GeoIPNetSpeed.dat");
   232 		GeoIPDBFileName[GEOIP_DOMAIN_EDITION]		= _GeoIP_full_path_to("GeoIPDomain.dat");
   233 	}
   234 }
   235 
   236 static
   237 int _file_exists(const char *file_name) {
   238 	struct stat file_stat;
   239 	return( (stat(file_name, &file_stat) == 0) ? 1:0);
   240 }
   241 
   242 int GeoIP_db_avail(int type) {
   243 	const char * filePath;
   244 	if (type < 0 || type >= NUM_DB_TYPES) {
   245 		return 0;
   246 	}
   247 	filePath = GeoIPDBFileName[type];
   248 	if (NULL == filePath) {
   249 		return 0;
   250 	}
   251 	return _file_exists(filePath);
   252 }
   253 
   254 static
   255 void _setup_segments(GeoIP * gi) {
   256 	int i, j;
   257 	unsigned char delim[3];
   258 	unsigned char buf[SEGMENT_RECORD_LENGTH];
   259 
   260 	gi->databaseSegments = NULL;
   261 
   262 	/* default to GeoIP Country Edition */
   263 	gi->databaseType = GEOIP_COUNTRY_EDITION;
   264 	gi->record_length = STANDARD_RECORD_LENGTH;
   265 	fseek(gi->GeoIPDatabase, -3l, SEEK_END);
   266 	for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
   267 		fread(delim, 1, 3, gi->GeoIPDatabase);
   268 		if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
   269 			fread(&gi->databaseType, 1, 1, gi->GeoIPDatabase);
   270 			if (gi->databaseType >= 106) {
   271 				/* backwards compatibility with databases from April 2003 and earlier */
   272 				gi->databaseType -= 105;
   273 			}
   274 
   275 			if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
   276 				/* Region Edition, pre June 2003 */
   277 				gi->databaseSegments = malloc(sizeof(int));
   278 				gi->databaseSegments[0] = STATE_BEGIN_REV0;
   279 			} else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
   280 				/* Region Edition, post June 2003 */
   281 				gi->databaseSegments = malloc(sizeof(int));
   282 				gi->databaseSegments[0] = STATE_BEGIN_REV1;
   283 			} else if (gi->databaseType == GEOIP_CITY_EDITION_REV0 ||
   284 								 gi->databaseType == GEOIP_CITY_EDITION_REV1 ||
   285 								 gi->databaseType == GEOIP_ORG_EDITION ||
   286 								 gi->databaseType == GEOIP_ISP_EDITION ||
   287 								 gi->databaseType == GEOIP_ASNUM_EDITION) {
   288 				/* City/Org Editions have two segments, read offset of second segment */
   289 				gi->databaseSegments = malloc(sizeof(int));
   290 				gi->databaseSegments[0] = 0;
   291 				fread(buf, SEGMENT_RECORD_LENGTH, 1, gi->GeoIPDatabase);
   292 				for (j = 0; j < SEGMENT_RECORD_LENGTH; j++) {
   293 					gi->databaseSegments[0] += (buf[j] << (j * 8));
   294 				}
   295 				if (gi->databaseType == GEOIP_ORG_EDITION ||
   296 						gi->databaseType == GEOIP_ISP_EDITION)
   297 					gi->record_length = ORG_RECORD_LENGTH;
   298 			}
   299 			break;
   300 		} else {
   301 			fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
   302 		}
   303 	}
   304 	if (gi->databaseType == GEOIP_COUNTRY_EDITION ||
   305 			gi->databaseType == GEOIP_PROXY_EDITION ||
   306 			gi->databaseType == GEOIP_NETSPEED_EDITION) {
   307 		gi->databaseSegments = malloc(sizeof(int));
   308 		gi->databaseSegments[0] = COUNTRY_BEGIN;
   309 	}
   310 }
   311 
   312 static
   313 int _check_mtime(GeoIP *gi) {
   314 	struct stat buf;
   315 	if (gi->flags & GEOIP_CHECK_CACHE) {
   316 		if (stat(gi->file_path, &buf) != -1) {
   317 			if (buf.st_mtime != gi->mtime) {
   318 				/* GeoIP Database file updated */
   319 				if (gi->flags & GEOIP_MEMORY_CACHE) {
   320 					/* reload database into memory cache */
   321 					if ((gi->cache = (unsigned char*) realloc(gi->cache, buf.st_size)) == NULL) {
   322 						fprintf(stderr,"Out of memory when reloading %s\n",gi->file_path);
   323 						return -1;
   324 					}
   325 				}
   326 				/* refresh filehandle */
   327 				fclose(gi->GeoIPDatabase);
   328 				gi->GeoIPDatabase = fopen(gi->file_path,"rb");
   329 				if (gi->GeoIPDatabase == NULL) {
   330 					fprintf(stderr,"Error Opening file %s when reloading\n",gi->file_path);
   331 					return -1;
   332 				}
   333 				gi->mtime = buf.st_mtime;
   334 				if (gi->flags & GEOIP_MEMORY_CACHE) {
   335 					if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
   336 						fprintf(stderr,"Error reading file %s when reloading\n",gi->file_path);
   337 						return -1;
   338 					}
   339 				}
   340 				if (gi->databaseSegments != NULL) {
   341 					free(gi->databaseSegments);
   342 					gi->databaseSegments = NULL;
   343 				}
   344 				_setup_segments(gi);
   345 				if (gi->databaseSegments == NULL) {
   346 					fprintf(stderr, "Error reading file %s -- corrupt\n", gi->file_path);
   347 					return -1;
   348 				}
   349 				if (gi->flags & GEOIP_INDEX_CACHE) {                        
   350 					gi->index_cache = (unsigned char *) realloc(gi->index_cache, sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
   351 					if (gi->index_cache != NULL) {
   352 						fseek(gi->GeoIPDatabase, 0, SEEK_SET);
   353 						if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0] * (long)gi->record_length * 2, gi->GeoIPDatabase) != (size_t) (gi->databaseSegments[0]*(long)gi->record_length * 2)) {
   354 							fprintf(stderr,"Error reading file %s where reloading\n",gi->file_path);
   355 							return -1;
   356 						}
   357 					}
   358 				}
   359 			}
   360 		}
   361 	}
   362 	return 0;
   363 }
   364 
   365 unsigned int _GeoIP_seek_record (GeoIP *gi, unsigned long ipnum) {
   366 	int depth;
   367 	unsigned int x;
   368 	unsigned char stack_buffer[2 * MAX_RECORD_LENGTH];
   369 	const unsigned char *buf = (gi->cache == NULL) ? stack_buffer : NULL;
   370 	unsigned int offset = 0;
   371 
   372 	const unsigned char * p;
   373 	int j;
   374 
   375 	_check_mtime(gi);
   376 	for (depth = 31; depth >= 0; depth--) {
   377 		if (gi->cache == NULL && gi->index_cache == NULL) {
   378 			/* read from disk */
   379 			fseek(gi->GeoIPDatabase, (long)gi->record_length * 2 * offset, SEEK_SET);
   380 			fread(stack_buffer,gi->record_length,2,gi->GeoIPDatabase);
   381 		} else if (gi->index_cache == NULL) {
   382 			/* simply point to record in memory */
   383 			buf = gi->cache + (long)gi->record_length * 2 *offset;
   384 		} else {
   385 			buf = gi->index_cache + (long)gi->record_length * 2 * offset;
   386 		}
   387 
   388 		if (ipnum & (1 << depth)) {
   389 			/* Take the right-hand branch */
   390 			if ( gi->record_length == 3 ) {
   391 				/* Most common case is completely unrolled and uses constants. */
   392 				x =   (buf[3*1 + 0] << (0*8))
   393 					+ (buf[3*1 + 1] << (1*8))
   394 					+ (buf[3*1 + 2] << (2*8));
   395 
   396 			} else {
   397 				/* General case */
   398 				j = gi->record_length;
   399 				p = &buf[2*j];
   400 				x = 0;
   401 				do {
   402 					x <<= 8;
   403 					x += *(--p);
   404 				} while ( --j );
   405 			}
   406 
   407 		} else {
   408 			/* Take the left-hand branch */
   409 			if ( gi->record_length == 3 ) {
   410 				/* Most common case is completely unrolled and uses constants. */
   411 				x =   (buf[3*0 + 0] << (0*8))
   412 					+ (buf[3*0 + 1] << (1*8))
   413 					+ (buf[3*0 + 2] << (2*8));
   414 			} else {
   415 				/* General case */
   416 				j = gi->record_length;
   417 				p = &buf[1*j];
   418 				x = 0;
   419 				do {
   420 					x <<= 8;
   421 					x += *(--p);
   422 				} while ( --j );
   423 			}
   424 		}
   425 
   426 		if (x >= gi->databaseSegments[0]) {
   427 			return x;
   428 		}
   429 		offset = x;
   430 	}
   431 
   432 	/* shouldn't reach here */
   433 	fprintf(stderr,"Error Traversing Database for ipnum = %lu - Perhaps database is corrupt?\n",ipnum);
   434 	return 0;
   435 }
   436 
   437 unsigned long _GeoIP_addr_to_num (const char *addr) {
   438 	int i;
   439 	char tok[4];
   440 	int octet;
   441 	int j = 0, k = 0;
   442 	unsigned long ipnum = 0;
   443 	char c = 0;
   444 
   445 	for (i=0; i<4; i++) {
   446 		for (;;) {
   447 			c = addr[k++];
   448 			if (c == '.' || c == '\0') {
   449 				tok[j] = '\0';
   450 				octet = atoi(tok);
   451 				if (octet > 255)
   452 					return 0;
   453 				ipnum += (octet << ((3-i)*8));
   454 				j = 0;
   455 				break;
   456 			} else if (c >= '0' && c<= '9') {
   457 				if (j > 2) {
   458 					return 0;
   459 				}
   460 				tok[j++] = c;
   461 			} else {
   462 				return 0;
   463 			}
   464 		}
   465 		if(c == '\0' && i<3) {
   466 			return 0;
   467 		}
   468 	}
   469 	return ipnum;
   470 }
   471 
   472 GeoIP* GeoIP_open_type (int type, int flags) {
   473 	GeoIP * gi;
   474 	const char * filePath;
   475 	if (type < 0 || type >= NUM_DB_TYPES) {
   476 		printf("Invalid database type %d\n", type);
   477 		return NULL;
   478 	}
   479 	_GeoIP_setup_dbfilename();
   480 	filePath = GeoIPDBFileName[type];
   481 	if (filePath == NULL) {
   482 		printf("Invalid database type %d\n", type);
   483 		return NULL;
   484 	}
   485 	gi = GeoIP_open (filePath, flags);
   486 	return gi;
   487 }
   488 
   489 GeoIP* GeoIP_new (int flags) {
   490 	GeoIP * gi;
   491 	_GeoIP_setup_dbfilename();
   492 	gi = GeoIP_open (GeoIPDBFileName[GEOIP_COUNTRY_EDITION], flags);
   493 	return gi;
   494 }
   495 
   496 GeoIP* GeoIP_open (const char * filename, int flags) {
   497 	struct stat buf;
   498 	GeoIP * gi;
   499 	size_t len;
   500 
   501 #ifdef _WIN32
   502 	WSADATA wsa;
   503 	if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
   504 		return NULL;
   505 #endif
   506 
   507 	gi = (GeoIP *)malloc(sizeof(GeoIP));
   508 	if (gi == NULL)
   509 		return NULL;
   510 	len = sizeof(char) * (strlen(filename)+1);
   511 	gi->file_path = malloc(len);
   512 	if (gi->file_path == NULL) {
   513 		free(gi);
   514 		return NULL;
   515 	}
   516 	strncpy(gi->file_path, filename, len);
   517 	gi->GeoIPDatabase = fopen(filename,"rb");
   518 	if (gi->GeoIPDatabase == NULL) {
   519 		fprintf(stderr,"Error Opening file %s\n",filename);
   520 		free(gi->file_path);
   521 		free(gi);
   522 		return NULL;
   523 	} else {
   524 		if (flags & GEOIP_MEMORY_CACHE) {
   525 			if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
   526 				fprintf(stderr,"Error stating file %s\n",filename);
   527 				free(gi->file_path);
   528 				free(gi);
   529 				return NULL;
   530 			}
   531 			gi->mtime = buf.st_mtime;
   532 			gi->cache = (unsigned char *) malloc(sizeof(unsigned char) * buf.st_size);
   533 			if (gi->cache != NULL) {
   534 				if (fread(gi->cache, sizeof(unsigned char), buf.st_size, gi->GeoIPDatabase) != (size_t) buf.st_size) {
   535 					fprintf(stderr,"Error reading file %s\n",filename);
   536 					free(gi->cache);
   537 					free(gi->file_path);
   538 					free(gi);
   539 					return NULL;
   540 				}
   541 			}
   542 		} else {
   543 			if (flags & GEOIP_CHECK_CACHE) {
   544 				if (fstat(fileno(gi->GeoIPDatabase), &buf) == -1) {
   545 					fprintf(stderr,"Error stating file %s\n",filename);
   546 					free(gi->file_path);
   547 					free(gi);
   548 					return NULL;
   549 				}
   550 				gi->mtime = buf.st_mtime;
   551 			}
   552 			gi->cache = NULL;
   553 		}
   554 		gi->flags = flags;
   555 		_setup_segments(gi);
   556 		if (flags & GEOIP_INDEX_CACHE) {                        
   557 			gi->index_cache = (unsigned char *) malloc(sizeof(unsigned char) * ((gi->databaseSegments[0] * (long)gi->record_length * 2)));
   558 			if (gi->index_cache != NULL) {
   559 				fseek(gi->GeoIPDatabase, 0, SEEK_SET);
   560 				if (fread(gi->index_cache, sizeof(unsigned char), gi->databaseSegments[0] * (long)gi->record_length * 2, gi->GeoIPDatabase) != (size_t) (gi->databaseSegments[0]*(long)gi->record_length * 2)) {
   561 					fprintf(stderr,"Error reading file %s\n",filename);
   562 					free(gi->databaseSegments);
   563 					free(gi->index_cache);
   564 					free(gi);
   565 					return NULL;
   566 				}
   567 			}
   568 		} else {
   569 			gi->index_cache = NULL;
   570 		}
   571 		return gi;
   572 	}
   573 }
   574 
   575 void GeoIP_delete (GeoIP *gi) {
   576 	if (gi == NULL )
   577 		return;
   578 	if (gi->GeoIPDatabase != NULL)
   579 		fclose(gi->GeoIPDatabase);
   580 	if (gi->cache != NULL)
   581 		free(gi->cache);
   582 	if (gi->index_cache != NULL)
   583 		free(gi->index_cache);
   584 	if (gi->file_path != NULL)
   585 		free(gi->file_path);
   586 	if (gi->databaseSegments != NULL)
   587 		free(gi->databaseSegments);
   588 	free(gi);
   589 }
   590 
   591 const char *GeoIP_country_code_by_name (GeoIP* gi, const char *name) {
   592 	int country_id;
   593 	country_id = GeoIP_id_by_name(gi, name);
   594 	return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
   595 }
   596 
   597 const char *GeoIP_country_code3_by_name (GeoIP* gi, const char *name) {
   598 	int country_id;
   599 	country_id = GeoIP_id_by_name(gi, name);
   600 	return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
   601 }
   602 
   603 const char *GeoIP_country_name_by_name (GeoIP* gi, const char *name) {
   604 	int country_id;
   605 	country_id = GeoIP_id_by_name(gi, name);
   606 	return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
   607 }
   608 
   609 unsigned long _GeoIP_lookupaddress (const char *host) {
   610 	unsigned long addr = inet_addr(host);
   611 	struct hostent phe2;
   612 	struct hostent * phe = &phe2;
   613 	char *buf = NULL;
   614 	int result = 0;
   615 #ifdef HAVE_GETHOSTBYNAME_R
   616 	buf = malloc(buflength);
   617 #endif
   618 	if (addr == INADDR_NONE) {
   619 #ifdef HAVE_GETHOSTBYNAME_R
   620 		while (1) {
   621 			/* we use gethostbyname_r here because it is thread-safe and gethostbyname is not */
   622 #ifdef GETHOSTBYNAME_R_RETURNS_INT
   623 			result = gethostbyname_r(host,&phe2,buf,buflength,&phe,&herr);
   624 #else
   625 			phe = gethostbyname_r(host,&phe2,buf,buflength,&herr);
   626 #endif
   627 			if (herr != ERANGE)
   628 				break;
   629 			if (result == 0)
   630 				break;
   631 			/* double the buffer if the buffer is too small */
   632 			buflength = buflength * 2;
   633 			buf = realloc(buf,buflength);
   634 		}
   635 #endif
   636 #ifndef HAVE_GETHOSTBYNAME_R
   637 		/* Some systems do not support gethostbyname_r, such as Mac OS X */
   638 		phe = gethostbyname(host);
   639 #endif
   640 		if (!phe || result != 0) {
   641 			free(buf);
   642 			return 0;
   643 		}
   644 		addr = *((unsigned long *) phe->h_addr_list[0]);
   645 	}
   646 #ifdef HAVE_GETHOSTBYNAME_R
   647 	free(buf);
   648 #endif
   649 	return ntohl(addr);
   650 }
   651 
   652 int GeoIP_id_by_name (GeoIP* gi, const char *name) {
   653 	unsigned long ipnum;
   654 	int ret;
   655 	if (name == NULL) {
   656 		return 0;
   657 	}
   658 	if (gi->databaseType != GEOIP_COUNTRY_EDITION && gi->databaseType != GEOIP_PROXY_EDITION && gi->databaseType != GEOIP_NETSPEED_EDITION) {
   659 		printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
   660 		return 0;
   661 	}
   662 	if (!(ipnum = _GeoIP_lookupaddress(name)))
   663 		return 0;
   664 	ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
   665 	return ret;
   666 
   667 }
   668 
   669 const char *GeoIP_country_code_by_addr (GeoIP* gi, const char *addr) {
   670 	int country_id;
   671 	country_id = GeoIP_id_by_addr(gi, addr);
   672 	return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
   673 }
   674 
   675 const char *GeoIP_country_code3_by_addr (GeoIP* gi, const char *addr) {
   676 	int country_id;
   677 	country_id = GeoIP_id_by_addr(gi, addr);
   678 	return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
   679 	return GeoIP_country_code3[country_id];
   680 }
   681 
   682 const char *GeoIP_country_name_by_addr (GeoIP* gi, const char *addr) {
   683 	int country_id;
   684 	country_id = GeoIP_id_by_addr(gi, addr);
   685 	return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
   686 	return GeoIP_country_name[country_id];
   687 }
   688 
   689 const char *GeoIP_country_name_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   690 	int country_id;
   691 	country_id = GeoIP_id_by_ipnum(gi, ipnum);
   692 	return (country_id > 0) ? GeoIP_country_name[country_id] : NULL;
   693 } 
   694 
   695 const char *GeoIP_country_code_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   696 	int country_id;
   697 	country_id = GeoIP_id_by_ipnum(gi, ipnum);
   698 	return (country_id > 0) ? GeoIP_country_code[country_id] : NULL;
   699 }
   700 
   701 const char *GeoIP_country_code3_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   702 	int country_id;
   703 	country_id = GeoIP_id_by_ipnum(gi, ipnum);
   704 	return (country_id > 0) ? GeoIP_country_code3[country_id] : NULL;
   705 }
   706 
   707 int GeoIP_country_id_by_addr (GeoIP* gi, const char *addr) {
   708 	return GeoIP_id_by_addr(gi, addr);
   709 }
   710 
   711 int GeoIP_country_id_by_name (GeoIP* gi, const char *host) {
   712 	return GeoIP_id_by_name(gi, host);
   713 }
   714 
   715 int GeoIP_id_by_addr (GeoIP* gi, const char *addr) {
   716 	unsigned long ipnum;
   717 	int ret;
   718 	if (addr == NULL) {
   719 		return 0;
   720 	}
   721 	if (gi->databaseType != GEOIP_COUNTRY_EDITION &&
   722 			gi->databaseType != GEOIP_PROXY_EDITION &&
   723 			gi->databaseType != GEOIP_NETSPEED_EDITION) {
   724 		printf("Invalid database type %s, expected %s\n",
   725 					 GeoIPDBDescription[(int)gi->databaseType],
   726 					 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
   727 		return 0;
   728 	}
   729 	ipnum = _GeoIP_addr_to_num(addr);
   730 	ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
   731 	return ret;
   732 }
   733 
   734 int GeoIP_id_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   735 	int ret;
   736 	if (ipnum == 0) {
   737 		return 0;
   738 	}
   739 	if (gi->databaseType != GEOIP_COUNTRY_EDITION && 
   740 			gi->databaseType != GEOIP_PROXY_EDITION &&
   741 			gi->databaseType != GEOIP_NETSPEED_EDITION) {
   742 		printf("Invalid database type %s, expected %s\n",
   743 					 GeoIPDBDescription[(int)gi->databaseType],
   744 					 GeoIPDBDescription[GEOIP_COUNTRY_EDITION]);
   745 		return 0;
   746 	}
   747 	ret = _GeoIP_seek_record(gi, ipnum) - COUNTRY_BEGIN;
   748 	return ret;
   749 }
   750 
   751 char *GeoIP_database_info (GeoIP* gi) {
   752 	int i;
   753 	unsigned char buf[3];
   754 	char *retval;
   755 	int hasStructureInfo = 0;
   756 
   757 	if(gi == NULL)
   758 		return NULL;
   759 
   760 	_check_mtime(gi);
   761 	fseek(gi->GeoIPDatabase, -3l, SEEK_END);
   762 
   763 	/* first get past the database structure information */
   764 	for (i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
   765 		fread(buf, 1, 3, gi->GeoIPDatabase);
   766 		if (buf[0] == 255 && buf[1] == 255 && buf[2] == 255) {
   767 			hasStructureInfo = 1;
   768 			break;
   769 		}
   770 		fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
   771 	}
   772 	if (hasStructureInfo == 1) {
   773 		fseek(gi->GeoIPDatabase, -3l, SEEK_CUR);
   774 	} else {
   775 		/* no structure info, must be pre Sep 2002 database, go back to end */
   776 		fseek(gi->GeoIPDatabase, -3l, SEEK_END);
   777 	}
   778 
   779 	for (i = 0; i < DATABASE_INFO_MAX_SIZE; i++) {
   780 		fread(buf, 1, 3, gi->GeoIPDatabase);
   781 		if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) {
   782 			retval = malloc(sizeof(char) * (i+1));
   783 			if (retval == NULL) {
   784 				return NULL;
   785 			}
   786 			fread(retval, 1, i, gi->GeoIPDatabase);
   787 			retval[i] = '\0';
   788 			return retval;
   789 		}
   790 		fseek(gi->GeoIPDatabase, -4l, SEEK_CUR);
   791 	}
   792 	return NULL;
   793 }
   794 
   795 /* GeoIP Region Edition functions */
   796 
   797 void GeoIP_assign_region_by_inetaddr(GeoIP* gi, unsigned long inetaddr, GeoIPRegion *region) {
   798 	unsigned int seek_region;
   799 
   800 	/* This also writes in the terminating NULs (if you decide to
   801 	 * keep them) and clear any fields that are not set. */
   802 	memset(region, 0, sizeof(GeoIPRegion));
   803 
   804 	seek_region = _GeoIP_seek_record(gi, ntohl(inetaddr));
   805 
   806 	if (gi->databaseType == GEOIP_REGION_EDITION_REV0) {
   807 		/* Region Edition, pre June 2003 */
   808 		seek_region -= STATE_BEGIN_REV0;
   809 		if (seek_region >= 1000) {
   810 			region->country_code[0] = 'U';
   811 			region->country_code[1] = 'S';
   812 			region->region[0] = (char) ((seek_region - 1000)/26 + 65);
   813 			region->region[1] = (char) ((seek_region - 1000)%26 + 65);
   814 		} else {
   815 			memcpy(region->country_code, GeoIP_country_code[seek_region], 2);
   816 		}
   817 	} else if (gi->databaseType == GEOIP_REGION_EDITION_REV1) {
   818 		/* Region Edition, post June 2003 */
   819 		seek_region -= STATE_BEGIN_REV1;
   820 		if (seek_region < US_OFFSET) {
   821 			/* Unknown */
   822 			/* we don't need to do anything here b/c we memset region to 0 */
   823 		} else if (seek_region < CANADA_OFFSET) {
   824 			/* USA State */
   825 			region->country_code[0] = 'U';
   826 			region->country_code[1] = 'S';
   827 			region->region[0] = (char) ((seek_region - US_OFFSET)/26 + 65);
   828 			region->region[1] = (char) ((seek_region - US_OFFSET)%26 + 65);
   829 		} else if (seek_region < WORLD_OFFSET) {
   830 			/* Canada Province */
   831 			region->country_code[0] = 'C';
   832 			region->country_code[1] = 'A';
   833 			region->region[0] = (char) ((seek_region - CANADA_OFFSET)/26 + 65);
   834 			region->region[1] = (char) ((seek_region - CANADA_OFFSET)%26 + 65);
   835 		} else {
   836 			/* Not US or Canada */
   837 			memcpy(region->country_code, GeoIP_country_code[(seek_region - WORLD_OFFSET) / FIPS_RANGE], 2);
   838 		}
   839 	}
   840 }
   841 
   842 static
   843 GeoIPRegion * _get_region(GeoIP* gi, unsigned long ipnum) {
   844 	GeoIPRegion * region;
   845  
   846 	region = malloc(sizeof(GeoIPRegion));
   847 	if (region) {
   848 		GeoIP_assign_region_by_inetaddr(gi, htonl(ipnum), region);
   849 	}
   850 	return region;
   851 }
   852 
   853 GeoIPRegion * GeoIP_region_by_addr (GeoIP* gi, const char *addr) {
   854 	unsigned long ipnum;
   855 	if (addr == NULL) {
   856 		return 0;
   857 	}
   858 	if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
   859 			gi->databaseType != GEOIP_REGION_EDITION_REV1) {
   860 		printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
   861 		return 0;
   862 	}
   863 	ipnum = _GeoIP_addr_to_num(addr);
   864 	return _get_region(gi, ipnum);
   865 }
   866 
   867 GeoIPRegion * GeoIP_region_by_name (GeoIP* gi, const char *name) {
   868 	unsigned long ipnum;
   869 	if (name == NULL) {
   870 		return 0;
   871 	}
   872 	if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
   873 			gi->databaseType != GEOIP_REGION_EDITION_REV1) {
   874 		printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
   875 		return 0;
   876 	}
   877 	if (!(ipnum = _GeoIP_lookupaddress(name)))
   878 		return 0;
   879 	return _get_region(gi, ipnum);
   880 }
   881 
   882 GeoIPRegion * GeoIP_region_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   883 	if (gi->databaseType != GEOIP_REGION_EDITION_REV0 &&
   884 			gi->databaseType != GEOIP_REGION_EDITION_REV1) {
   885 		printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_REGION_EDITION_REV1]);
   886 		return 0;
   887 	}
   888 	return _get_region(gi, ipnum);
   889 }
   890 
   891 void GeoIPRegion_delete (GeoIPRegion *gir) {
   892 	free(gir);
   893 }
   894 
   895 /* GeoIP Organization, ISP and AS Number Edition private method */
   896 static
   897 char *_get_name (GeoIP* gi, unsigned long ipnum) {
   898 	int seek_org;
   899 	char buf[MAX_ORG_RECORD_LENGTH];
   900 	char * org_buf, * buf_pointer;
   901 	int record_pointer;
   902 	size_t len;
   903 
   904 	if (gi->databaseType != GEOIP_ORG_EDITION &&
   905 			gi->databaseType != GEOIP_ISP_EDITION &&
   906 			gi->databaseType != GEOIP_ASNUM_EDITION) {
   907 		printf("Invalid database type %s, expected %s\n", GeoIPDBDescription[(int)gi->databaseType], GeoIPDBDescription[GEOIP_ORG_EDITION]);
   908 		return 0;
   909 	}
   910 
   911 	seek_org = _GeoIP_seek_record(gi, ipnum);
   912 	if (seek_org == gi->databaseSegments[0])		
   913 		return NULL;
   914 
   915 	record_pointer = seek_org + (2 * gi->record_length - 1) * gi->databaseSegments[0];
   916 
   917 	if (gi->cache == NULL) {
   918 		fseek(gi->GeoIPDatabase, record_pointer, SEEK_SET);
   919 		fread(buf, sizeof(char), MAX_ORG_RECORD_LENGTH, gi->GeoIPDatabase);
   920 		len = sizeof(char) * (strlen(buf)+1);
   921 		org_buf = malloc(len);
   922 		strncpy(org_buf, buf, len);
   923 	} else {
   924 		buf_pointer = (char *)(gi->cache + (long)record_pointer);
   925 		len = sizeof(char) * (strlen(buf_pointer)+1);
   926 		org_buf = malloc(len);
   927 		strncpy(org_buf, buf_pointer, len);
   928 	}
   929 	return org_buf;
   930 }
   931 
   932 char *GeoIP_name_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   933 	return _get_name(gi,ipnum);  
   934 }
   935 
   936 char *GeoIP_name_by_addr (GeoIP* gi, const char *addr) {
   937 	unsigned long ipnum;
   938 	if (addr == NULL) {
   939 		return 0;
   940 	}
   941 	ipnum = _GeoIP_addr_to_num(addr);
   942 	return _get_name(gi, ipnum);
   943 }
   944 
   945 char *GeoIP_name_by_name (GeoIP* gi, const char *name) {
   946 	unsigned long ipnum;
   947 	if (name == NULL) {
   948 		return 0;
   949 	}
   950 	if (!(ipnum = _GeoIP_lookupaddress(name)))
   951 		return 0;
   952 	return _get_name(gi, ipnum);
   953 }
   954 
   955 char *GeoIP_org_by_ipnum (GeoIP* gi, unsigned long ipnum) {
   956 	return GeoIP_name_by_ipnum(gi, ipnum);
   957 }
   958 
   959 char *GeoIP_org_by_addr (GeoIP* gi, const char *addr) {
   960 	return GeoIP_name_by_addr(gi, addr);
   961 }
   962 
   963 char *GeoIP_org_by_name (GeoIP* gi, const char *name) {
   964 	return GeoIP_name_by_name(gi, name);
   965 }
   966 
   967 unsigned char GeoIP_database_edition (GeoIP* gi) {
   968 	return gi->databaseType;
   969 }